Merge "Reland: Crop surface to the content size during drag-resizing" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 7005349..aabe87f 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -18,11 +18,19 @@
 
     // Add java_aconfig_libraries to here to add them to the core framework
     srcs: [
+        ":android.app.usage.flags-aconfig-java{.generated_srcjars}",
+        ":android.os.flags-aconfig-java{.generated_srcjars}",
+        ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
         ":android.security.flags-aconfig-java{.generated_srcjars}",
         ":camera_platform_flags_core_java_lib{.generated_srcjars}",
         ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
         ":com.android.text.flags-aconfig-java{.generated_srcjars}",
+        ":telecom_flags_core_java_lib{.generated_srcjars}",
+        ":android.companion.virtual.flags-aconfig-java{.generated_srcjars}",
+        ":android.view.inputmethod.flags-aconfig-java{.generated_srcjars}",
     ],
+    // Add aconfig-annotations-lib as a dependency for the optimization
+    libs: ["aconfig-annotations-lib"],
 }
 
 // Default flags for java_aconfig_libraries that go into framework-minus-apex
@@ -40,6 +48,13 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+// Telecom
+java_aconfig_library {
+    name: "telecom_flags_core_java_lib",
+    aconfig_declarations: "telecom_flags",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // Window
 aconfig_declarations {
     name: "com.android.window.flags.window-aconfig",
@@ -66,6 +81,11 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+cc_aconfig_library {
+    name: "aconfig_text_flags_c_lib",
+    aconfig_declarations: "com.android.text.flags-aconfig",
+}
+
 // Security
 aconfig_declarations {
     name: "android.security.flags-aconfig",
@@ -78,3 +98,76 @@
     aconfig_declarations: "android.security.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+java_aconfig_library {
+    name: "android.security.flags-aconfig-java-host",
+    aconfig_declarations: "android.security.flags-aconfig",
+    host_supported: true,
+    test: true,
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// UsageStats
+aconfig_declarations {
+    name: "android.app.usage.flags-aconfig",
+    package: "android.app.usage",
+    srcs: ["core/java/android/app/usage/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.app.usage.flags-aconfig-java",
+    aconfig_declarations: "android.app.usage.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// OS
+aconfig_declarations {
+    name: "android.os.flags-aconfig",
+    package: "android.os",
+    srcs: ["core/java/android/os/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.os.flags-aconfig-java",
+    aconfig_declarations: "android.os.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// VirtualDeviceManager
+java_aconfig_library {
+    name: "android.companion.virtual.flags-aconfig-java",
+    aconfig_declarations: "android.companion.virtual.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+aconfig_declarations {
+    name: "android.companion.virtual.flags-aconfig",
+    package: "android.companion.virtual.flags",
+    srcs: ["core/java/android/companion/virtual/*.aconfig"],
+}
+
+// InputMethod
+aconfig_declarations {
+    name: "android.view.inputmethod.flags-aconfig",
+    package: "android.view.inputmethod",
+    srcs: ["core/java/android/view/inputmethod/flags.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.view.inputmethod.flags-aconfig-java",
+    aconfig_declarations: "android.view.inputmethod.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// Vibrator
+aconfig_declarations {
+    name: "android.os.vibrator.flags-aconfig",
+    package: "android.os.vibrator",
+    srcs: ["core/java/android/os/vibrator/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.os.vibrator.flags-aconfig-java",
+    aconfig_declarations: "android.os.vibrator.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index 431f0b9..57a5a3c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -71,7 +71,6 @@
         ":framework-jobscheduler-sources", // jobscheduler is not a module for R
         ":framework-keystore-sources",
         ":framework-identity-sources",
-        ":framework-location-sources",
         ":framework-mca-effect-sources",
         ":framework-mca-filterfw-sources",
         ":framework-mca-filterpacks-sources",
@@ -163,6 +162,12 @@
         //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__",
     ],
 }
 
@@ -177,7 +182,6 @@
             "graphics/java",
             "identity/java",
             "keystore/java",
-            "location/java",
             "media/java",
             "media/mca/effect/java",
             "media/mca/filterfw/java",
@@ -287,7 +291,6 @@
             ":framework-jobscheduler-sources",
             ":framework-keystore-sources",
             ":framework-identity-sources",
-            ":framework-location-sources",
             ":framework-mca-effect-sources",
             ":framework-mca-filterfw-sources",
             ":framework-mca-filterpacks-sources",
@@ -405,6 +408,7 @@
         "audiopolicy-aidl-java",
         "sounddose-aidl-java",
         "modules-utils-expresslog",
+        "hoststubgen-annotations",
     ],
 }
 
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 9d363c8..3af36eb 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -28,6 +28,7 @@
 import static android.os.UserHandle.USER_CURRENT;
 import static android.os.UserHandle.USER_NULL;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
 import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID;
 import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE;
 import static com.android.server.blob.BlobStoreConfig.LOGV;
@@ -1915,7 +1916,7 @@
         mStatsManager.setPullAtomCallback(
                 FrameworkStatsLog.BLOB_INFO,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 mStatsCallbackImpl
         );
     }
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 17076bc..66c1efc 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -419,6 +419,14 @@
      */
     public static final int REASON_SYSTEM_EXEMPT_APP_OP = 327;
 
+    /**
+     * Granted by {@link com.android.server.pm.PackageArchiverService} to the installer responsible
+     * for unarchiving an app.
+     *
+     * @hide
+     */
+    public static final int REASON_PACKAGE_UNARCHIVE = 328;
+
     /** @hide The app requests out-out. */
     public static final int REASON_OPT_OUT_REQUESTED = 1000;
 
@@ -502,6 +510,7 @@
             REASON_ACTIVE_DEVICE_ADMIN,
             REASON_MEDIA_NOTIFICATION_TRANSFER,
             REASON_PACKAGE_INSTALLER,
+            REASON_PACKAGE_UNARCHIVE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ReasonCode {}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 1be07fd..b8596d5 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -538,7 +538,7 @@
 
     /**
      * Package names the system has white-listed to opt out of power save restrictions,
-     * except for device idle mode.
+     * except for device idle modes (light and full doze).
      */
     private final ArrayMap<String, Integer> mPowerSaveWhitelistAppsExceptIdle = new ArrayMap<>();
 
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
index 90a6455a..adb4d85 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/MetricsHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.server.alarm;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__ALLOW_LIST;
 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__CHANGE_DISABLED;
 import static com.android.internal.util.FrameworkStatsLog.ALARM_SCHEDULED__EXACT_ALARM_ALLOWED_REASON__LISTENER;
@@ -31,7 +32,6 @@
 import android.content.Context;
 import android.os.SystemClock;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FrameworkStatsLog;
 
 import java.util.function.Supplier;
@@ -51,7 +51,7 @@
     void registerPuller(Supplier<AlarmStore> alarmStoreSupplier) {
         final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
         statsManager.setPullAtomCallback(FrameworkStatsLog.PENDING_ALARM_INFO, null,
-                BackgroundThread.getExecutor(), (atomTag, data) -> {
+                DIRECT_EXECUTOR, (atomTag, data) -> {
                     if (atomTag != FrameworkStatsLog.PENDING_ALARM_INFO) {
                         throw new UnsupportedOperationException("Unknown tag" + atomTag);
                     }
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index 2a9375c..19d6f04 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -12682,7 +12682,6 @@
 com.android.internal.util.LatencyTracker$Action
 com.android.internal.util.LatencyTracker$ActionProperties
 com.android.internal.util.LatencyTracker$FrameworkStatsLogEvent
-com.android.internal.util.LatencyTracker$SLatencyTrackerHolder
 com.android.internal.util.LatencyTracker$Session$$ExternalSyntheticLambda0
 com.android.internal.util.LatencyTracker$Session
 com.android.internal.util.LatencyTracker
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 28db61f..4e41f2c 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -49,7 +49,7 @@
 
     virtual void onVmCreated(JNIEnv* env)
     {
-        if (mClassName.isEmpty()) {
+        if (mClassName.empty()) {
             return; // Zygote. Nothing to do here.
         }
 
@@ -66,10 +66,10 @@
          * executing boot class Java code and thereby deny ourselves access to
          * non-boot classes.
          */
-        char* slashClassName = toSlashClassName(mClassName.string());
+        char* slashClassName = toSlashClassName(mClassName.c_str());
         mClass = env->FindClass(slashClassName);
         if (mClass == NULL) {
-            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
+            ALOGE("ERROR: could not find class '%s'\n", mClassName.c_str());
         }
         free(slashClassName);
 
@@ -98,7 +98,7 @@
 
     virtual void onExit(int code)
     {
-        if (mClassName.isEmpty()) {
+        if (mClassName.empty()) {
             // if zygote
             IPCThreadState::self()->stopProcess();
             hardware::IPCThreadState::self()->stopProcess();
@@ -179,7 +179,7 @@
         argv_String.append(argv[i]);
         argv_String.append("\" ");
       }
-      ALOGV("app_process main with argv: %s", argv_String.string());
+      ALOGV("app_process main with argv: %s", argv_String.c_str());
     }
 
     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
@@ -271,9 +271,9 @@
         } else if (strcmp(arg, "--application") == 0) {
             application = true;
         } else if (strncmp(arg, "--nice-name=", 12) == 0) {
-            niceName.setTo(arg + 12);
+            niceName = (arg + 12);
         } else if (strncmp(arg, "--", 2) != 0) {
-            className.setTo(arg);
+            className = arg;
             break;
         } else {
             --i;
@@ -282,7 +282,7 @@
     }
 
     Vector<String8> args;
-    if (!className.isEmpty()) {
+    if (!className.empty()) {
         // We're not in zygote mode, the only argument we need to pass
         // to RuntimeInit is the application argument.
         //
@@ -300,7 +300,7 @@
             restOfArgs.append(argv_new[k]);
             restOfArgs.append("\" ");
           }
-          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
+          ALOGV("Class name = %s, args = %s", className.c_str(), restOfArgs.c_str());
         }
     } else {
         // We're in zygote mode.
@@ -328,13 +328,13 @@
         }
     }
 
-    if (!niceName.isEmpty()) {
-        runtime.setArgv0(niceName.string(), true /* setProcName */);
+    if (!niceName.empty()) {
+        runtime.setArgv0(niceName.c_str(), true /* setProcName */);
     }
 
     if (zygote) {
         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
-    } else if (!className.isEmpty()) {
+    } else if (!className.empty()) {
         runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
     } else {
         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index b56dceb..f2d0efe 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -723,7 +723,7 @@
 bool BootAnimation::preloadAnimation() {
     ATRACE_CALL();
     findBootAnimationFile();
-    if (!mZipFileName.isEmpty()) {
+    if (!mZipFileName.empty()) {
         mAnimation = loadAnimation(mZipFileName);
         return (mAnimation != nullptr);
     }
@@ -842,7 +842,7 @@
 
     // We have no bootanimation file, so we use the stock android logo
     // animation.
-    if (mZipFileName.isEmpty()) {
+    if (mZipFileName.empty()) {
         ALOGD("No animation file");
         result = android();
     } else {
@@ -1041,7 +1041,7 @@
         return false;
     }
 
-    outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
+    outString = String8((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
     delete entryMap;
     return true;
 }
@@ -1171,7 +1171,7 @@
     if (!readFile(animation.zip, "desc.txt", desString)) {
         return false;
     }
-    char const* s = desString.string();
+    char const* s = desString.c_str();
     std::string dynamicColoringPartName = "";
     bool postDynamicColoring = false;
 
@@ -1180,7 +1180,7 @@
         const char* endl = strstr(s, "\n");
         if (endl == nullptr) break;
         String8 line(s, endl - s);
-        const char* l = line.string();
+        const char* l = line.c_str();
         int fps = 0;
         int width = 0;
         int height = 0;
@@ -1341,7 +1341,7 @@
                                     part.audioData = (uint8_t *)map->getDataPtr();
                                     part.audioLength = map->getDataLength();
                                 } else if (leaf == "trim.txt") {
-                                    part.trimData.setTo((char const*)map->getDataPtr(),
+                                    part.trimData = String8((char const*)map->getDataPtr(),
                                                         map->getDataLength());
                                 } else {
                                     Animation::Frame frame;
@@ -1365,7 +1365,7 @@
 
     // If there is trimData present, override the positioning defaults.
     for (Animation::Part& part : animation.parts) {
-        const char* trimDataStr = part.trimData.string();
+        const char* trimDataStr = part.trimData.c_str();
         for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
             const char* endl = strstr(trimDataStr, "\n");
             // No more trimData for this part.
@@ -1373,7 +1373,7 @@
                 break;
             }
             String8 line(trimDataStr, endl - trimDataStr);
-            const char* lineStr = line.string();
+            const char* lineStr = line.c_str();
             trimDataStr = ++endl;
             int width = 0, height = 0, x = 0, y = 0;
             if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
@@ -1432,7 +1432,7 @@
     if (!exts) {
         glGetError();
     } else {
-        gl_extensions.setTo(exts);
+        gl_extensions = exts;
         if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
             (gl_extensions.find("GL_OES_texture_npot") != -1)) {
             mUseNpotTextures = true;
@@ -1606,7 +1606,7 @@
                     1.0f);
 
             ALOGD("Playing files = %s/%s, Requested repeat = %d, playUntilComplete = %s",
-                    animation.fileName.string(), part.path.string(), part.count,
+                    animation.fileName.c_str(), part.path.c_str(), part.count,
                     part.playUntilComplete ? "true" : "false");
 
             // For the last animation, if we have progress indicator from
@@ -1831,17 +1831,17 @@
     ATRACE_CALL();
     if (mLoadedFiles.indexOf(fn) >= 0) {
         SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
-            fn.string());
+            fn.c_str());
         return nullptr;
     }
     ZipFileRO *zip = ZipFileRO::open(fn);
     if (zip == nullptr) {
         SLOGE("Failed to open animation zip \"%s\": %s",
-            fn.string(), strerror(errno));
+            fn.c_str(), strerror(errno));
         return nullptr;
     }
 
-    ALOGD("%s is loaded successfully", fn.string());
+    ALOGD("%s is loaded successfully", fn.c_str());
 
     Animation *animation =  new Animation;
     animation->fileName = fn;
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 174d85c..9d04a7f 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -96,7 +96,7 @@
       auto value = target_entry_value.second;
 
       print(target_entry_value.first.to_string(), false, "config: %s",
-          target_entry_value.first.toString().string());
+          target_entry_value.first.toString().c_str());
 
       print(value.data_type, "type: %s",
             utils::DataTypeToString(value.data_type).data());
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 1d78460..7807155 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -130,11 +130,14 @@
 }
 
 Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
+  String16 name16;
   return FindAttribute(parser_, name, [&](size_t index) -> bool {
-    size_t len;
-    const String16 key16(parser_.getAttributeName(index, &len));
-    std::string key = String8(key16).c_str();
-    return key == name;
+    if (name16.empty()) {
+        name16 = String16(name.c_str(), name.size());
+    }
+    size_t key_len;
+    const auto key16 = parser_.getAttributeName(index, &key_len);
+    return key16 && name16.size() == key_len && name16 == key16;
   });
 }
 
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index 6e0bd06..0d9f4e9 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -83,8 +83,8 @@
 Status
 StatusListener::onReportServiceStatus(const String16& service, int32_t status)
 {
-    fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
-    ALOGD("service '%s' status %d\n", String8(service).string(), status);
+    fprintf(stderr, "service '%s' status %d\n", String8(service).c_str(), status);
+    ALOGD("service '%s' status %d\n", String8(service).c_str(), status);
     return Status::ok();
 }
 
@@ -384,7 +384,7 @@
         status = service->reportIncidentToStream(args, listener, std::move(writeEnd));
 
         if (!status.isOk()) {
-            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().c_str());
             return 1;
         }
 
@@ -396,14 +396,14 @@
         sp<StatusListener> listener(new StatusListener());
         status = service->reportIncidentToDumpstate(std::move(writeEnd), listener);
         if (!status.isOk()) {
-            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().c_str());
             return 1;
         }
         return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
     } else {
         status = service->reportIncident(args);
         if (!status.isOk()) {
-            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+            fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().c_str());
             return 1;
         } else {
             return 0;
diff --git a/cmds/incident_helper/src/TextParserBase.cpp b/cmds/incident_helper/src/TextParserBase.cpp
index e9bc70f..e625afa 100644
--- a/cmds/incident_helper/src/TextParserBase.cpp
+++ b/cmds/incident_helper/src/TextParserBase.cpp
@@ -27,11 +27,11 @@
 {
     string content;
     if (!ReadFdToString(in, &content)) {
-        fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
+        fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.c_str());
         return -1;
     }
     if (!WriteStringToFd(content, out)) {
-        fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
+        fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.c_str());
         return -1;
     }
     return NO_ERROR;
@@ -42,13 +42,13 @@
 {
     string content;
     if (!ReadFdToString(in, &content)) {
-        fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
+        fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.c_str());
         return -1;
     }
     // reverse the content
     reverse(content.begin(), content.end());
     if (!WriteStringToFd(content, out)) {
-        fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
+        fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.c_str());
         return -1;
     }
     return NO_ERROR;
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index ff5fd86..cc03d4a 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -101,7 +101,7 @@
     fprintf(stderr, "Pasring section %d...\n", sectionID);
     TextParserBase* parser = selectParser(sectionID);
     if (parser != nullptr) {
-        fprintf(stderr, "Running parser: %s\n", parser->name.string());
+        fprintf(stderr, "Running parser: %s\n", parser->name.c_str());
         status_t err = parser->Parse(STDIN_FILENO, STDOUT_FILENO);
         if (err != NO_ERROR) {
             fprintf(stderr, "Parse error in section %d: %s\n", sectionID, strerror(-err));
diff --git a/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp b/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
index ced6cf8..2a032fb 100644
--- a/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
+++ b/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
@@ -52,9 +52,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
index 43a12f6..c9bf4c5 100644
--- a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
@@ -82,9 +82,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
index 5d525e6..77751a2f 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -130,11 +130,11 @@
         record = parseRecordByColumns(line, columnIndices);
         diff = record.size() - header.size();
         if (diff < 0) {
-            fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str());
+            fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.c_str(), nline, -diff, line.c_str());
             printRecord(record);
             continue;
         } else if (diff > 0) {
-            fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str());
+            fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.c_str(), nline, diff, line.c_str());
             printRecord(record);
             continue;
         }
@@ -143,7 +143,7 @@
         for (int i=0; i<(int)record.size(); i++) {
             if (!table.insertField(&proto, header[i], record[i])) {
                 fprintf(stderr, "[%s]Line %d fails to insert field %s with value %s\n",
-                        this->name.string(), nline, header[i].c_str(), record[i].c_str());
+                        this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
             }
         }
         proto.end(token);
@@ -155,9 +155,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp b/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
index 4fd6b06..0474a50 100644
--- a/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
+++ b/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
@@ -76,9 +76,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index 85beaf0..d16c23c 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -51,11 +51,11 @@
 
         if (record.size() < header.size()) {
             // TODO: log this to incident report!
-            fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline, line.c_str());
+            fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.c_str(), nline, line.c_str());
             continue;
         } else if (record.size() > header.size()) {
             // TODO: log this to incident report!
-            fprintf(stderr, "[%s]Line %d has extra fields\n%s\n", this->name.string(), nline, line.c_str());
+            fprintf(stderr, "[%s]Line %d has extra fields\n%s\n", this->name.c_str(), nline, line.c_str());
             continue;
         }
 
@@ -63,7 +63,7 @@
         for (int i=0; i<(int)record.size(); i++) {
             if (!table.insertField(&proto, header[i], record[i])) {
                 fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
-                        this->name.string(), nline, header[i].c_str(), record[i].c_str());
+                        this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
             }
         }
         proto.end(token);
@@ -75,9 +75,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
index 2a89c920..36710df 100644
--- a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -114,10 +114,10 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
 
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
index 4763b48..997d2e5 100644
--- a/cmds/incident_helper/src/parsers/ProcrankParser.cpp
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -60,7 +60,7 @@
             if (record[record.size() - 1] == "TOTAL") { // TOTAL record
                 total = line;
             } else {
-                fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline,
+                fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.c_str(), nline,
                     line.c_str());
             }
             continue;
@@ -70,7 +70,7 @@
         for (int i=0; i<(int)record.size(); i++) {
             if (!table.insertField(&proto, header[i], record[i])) {
                 fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
-                        this->name.string(), nline, header[i].c_str(), record[i].c_str());
+                        this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
             }
         }
         proto.end(token);
@@ -104,9 +104,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/PsParser.cpp b/cmds/incident_helper/src/parsers/PsParser.cpp
index d3cb4be..55aa555 100644
--- a/cmds/incident_helper/src/parsers/PsParser.cpp
+++ b/cmds/incident_helper/src/parsers/PsParser.cpp
@@ -61,12 +61,12 @@
         diff = record.size() - header.size();
         if (diff < 0) {
             // TODO: log this to incident report!
-            fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str());
+            fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.c_str(), nline, -diff, line.c_str());
             printRecord(record);
             continue;
         } else if (diff > 0) {
             // TODO: log this to incident report!
-            fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str());
+            fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.c_str(), nline, diff, line.c_str());
             printRecord(record);
             continue;
         }
@@ -75,7 +75,7 @@
         for (int i=0; i<(int)record.size(); i++) {
             if (!table.insertField(&proto, header[i], record[i])) {
                 fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
-                        this->name.string(), nline, header[i].c_str(), record[i].c_str());
+                        this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
             }
         }
         proto.end(token);
@@ -87,9 +87,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
index eba536b..86c34bc 100644
--- a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
@@ -219,9 +219,9 @@
     }
 
     if (!proto.flush(out)) {
-        fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+        fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
         return -1;
     }
-    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+    fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
     return NO_ERROR;
 }
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 4f9059f..e70748e8 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -407,8 +407,8 @@
 Status IncidentService::getIncidentReportList(const String16& pkg16, const String16& cls16,
             vector<String16>* result) {
     status_t err;
-    const string pkg(String8(pkg16).string());
-    const string cls(String8(cls16).string());
+    const string pkg(String8(pkg16).c_str());
+    const string cls(String8(cls16).c_str());
 
     // List the reports
     vector<sp<ReportFile>> all;
@@ -441,9 +441,9 @@
             const String16& id16, IncidentManager::IncidentReport* result) {
     status_t err;
 
-    const string pkg(String8(pkg16).string());
-    const string cls(String8(cls16).string());
-    const string id(String8(id16).string());
+    const string pkg(String8(pkg16).c_str());
+    const string cls(String8(cls16).c_str());
+    const string id(String8(id16).c_str());
 
     IncidentReportArgs args;
     sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, &args);
@@ -470,9 +470,9 @@
 
 Status IncidentService::deleteIncidentReports(const String16& pkg16, const String16& cls16,
             const String16& id16) {
-    const string pkg(String8(pkg16).string());
-    const string cls(String8(cls16).string());
-    const string id(String8(id16).string());
+    const string pkg(String8(pkg16).c_str());
+    const string cls(String8(cls16).c_str());
+    const string id(String8(id16).c_str());
 
     sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, nullptr);
     if (file != nullptr) {
@@ -484,7 +484,7 @@
 }
 
 Status IncidentService::deleteAllIncidentReports(const String16& pkg16) {
-    const string pkg(String8(pkg16).string());
+    const string pkg(String8(pkg16).c_str());
 
     mWorkDirectory->commitAll(pkg);
     mBroadcaster->clearPackageBroadcasts(pkg);
@@ -572,7 +572,7 @@
             while (SECTION_LIST[idx] != NULL) {
                 const Section* section = SECTION_LIST[idx];
                 if (section->id == id) {
-                    fprintf(out, "Section[%d] %s\n", id, section->name.string());
+                    fprintf(out, "Section[%d] %s\n", id, section->name.c_str());
                     break;
                 }
                 idx++;
@@ -596,7 +596,7 @@
 
 static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
     if (p == NULL) return;
-    fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->policy);
+    fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.c_str(), p->field_id, p->type, p->policy);
     if (p->children == NULL) return;
     for (int i = 0; p->children[i] != NULL; i++) {  // NULL-terminated.
         printPrivacy(p->children[i], out, indent + "  ");
@@ -609,7 +609,7 @@
     const int argCount = args.size();
     if (argCount >= 3) {
         String8 opt = args[1];
-        int sectionId = atoi(args[2].string());
+        int sectionId = atoi(args[2].c_str());
 
         const Privacy* p = get_privacy_of_section(sectionId);
         if (p == NULL) {
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 86a78f09..c9cf727 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -711,7 +711,7 @@
         return NO_ERROR;
     }
 
-    ALOGD("Start incident report section %d '%s'", sectionId, section->name.string());
+    ALOGD("Start incident report section %d '%s'", sectionId, section->name.c_str());
     IncidentMetadata::SectionStats* sectionMetadata = metadata->add_sections();
 
     // Notify listener of starting
@@ -747,7 +747,7 @@
                     sectionId, IIncidentReportStatusListener::STATUS_FINISHED);
     });
 
-    ALOGD("Finish incident report section %d '%s'", sectionId, section->name.string());
+    ALOGD("Finish incident report section %d '%s'", sectionId, section->name.c_str());
     return NO_ERROR;
 }
 
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 581367a..c2aa269 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -60,7 +60,7 @@
 const char* GZIP[] = {"/system/bin/gzip", NULL};
 
 static pid_t fork_execute_incident_helper(const int id, Fpipe* p2cPipe, Fpipe* c2pPipe) {
-    const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
+    const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).c_str(), NULL};
     return fork_execute_cmd(const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
 }
 
@@ -100,7 +100,7 @@
     // add O_CLOEXEC to make sure it is closed when exec incident helper
     unique_fd fd(open(mFilename, O_RDONLY | O_CLOEXEC));
     if (fd.get() == -1) {
-        ALOGW("[%s] failed to open file", this->name.string());
+        ALOGW("[%s] failed to open file", this->name.c_str());
         // There may be some devices/architectures that won't have the file.
         // Just return here without an error.
         return NO_ERROR;
@@ -110,13 +110,13 @@
     Fpipe c2pPipe;
     // initiate pipes to pass data to/from incident_helper
     if (!p2cPipe.init() || !c2pPipe.init()) {
-        ALOGW("[%s] failed to setup pipes", this->name.string());
+        ALOGW("[%s] failed to setup pipes", this->name.c_str());
         return -errno;
     }
 
     pid_t pid = fork_execute_incident_helper(this->id, &p2cPipe, &c2pPipe);
     if (pid == -1) {
-        ALOGW("[%s] failed to fork", this->name.string());
+        ALOGW("[%s] failed to fork", this->name.c_str());
         return -errno;
     }
 
@@ -128,14 +128,14 @@
     writer->setSectionStats(buffer);
     if (readStatus != NO_ERROR || buffer.timedOut()) {
         ALOGW("[%s] failed to read data from incident helper: %s, timedout: %s",
-              this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+              this->name.c_str(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
         kill_child(pid);
         return readStatus;
     }
 
     status_t ihStatus = wait_child(pid);
     if (ihStatus != NO_ERROR) {
-        ALOGW("[%s] abnormal child process: %s", this->name.string(), strerror(-ihStatus));
+        ALOGW("[%s] abnormal child process: %s", this->name.c_str(), strerror(-ihStatus));
         return OK; // Not a fatal error.
     }
 
@@ -169,7 +169,7 @@
         index++;  // look at the next file.
     }
     if (fd.get() == -1) {
-        ALOGW("[%s] can't open all the files", this->name.string());
+        ALOGW("[%s] can't open all the files", this->name.c_str());
         return NO_ERROR;  // e.g. LAST_KMSG will reach here in user build.
     }
     FdBuffer buffer;
@@ -177,13 +177,13 @@
     Fpipe c2pPipe;
     // initiate pipes to pass data to/from gzip
     if (!p2cPipe.init() || !c2pPipe.init()) {
-        ALOGW("[%s] failed to setup pipes", this->name.string());
+        ALOGW("[%s] failed to setup pipes", this->name.c_str());
         return -errno;
     }
 
     pid_t pid = fork_execute_cmd((char* const*)GZIP, &p2cPipe, &c2pPipe);
     if (pid == -1) {
-        ALOGW("[%s] failed to fork", this->name.string());
+        ALOGW("[%s] failed to fork", this->name.c_str());
         return -errno;
     }
     // parent process
@@ -202,14 +202,14 @@
     size_t editPos = internalBuffer->wp()->pos();
     internalBuffer->wp()->move(8);  // reserve 8 bytes for the varint of the data size.
     size_t dataBeginAt = internalBuffer->wp()->pos();
-    VLOG("[%s] editPos=%zu, dataBeginAt=%zu", this->name.string(), editPos, dataBeginAt);
+    VLOG("[%s] editPos=%zu, dataBeginAt=%zu", this->name.c_str(), editPos, dataBeginAt);
 
     status_t readStatus = buffer.readProcessedDataInStream(
             fd.get(), std::move(p2cPipe.writeFd()), std::move(c2pPipe.readFd()), this->timeoutMs,
             isSysfs(mFilenames[index]));
     writer->setSectionStats(buffer);
     if (readStatus != NO_ERROR || buffer.timedOut()) {
-        ALOGW("[%s] failed to read data from gzip: %s, timedout: %s", this->name.string(),
+        ALOGW("[%s] failed to read data from gzip: %s, timedout: %s", this->name.c_str(),
               strerror(-readStatus), buffer.timedOut() ? "true" : "false");
         kill_child(pid);
         return readStatus;
@@ -217,7 +217,7 @@
 
     status_t gzipStatus = wait_child(pid);
     if (gzipStatus != NO_ERROR) {
-        ALOGW("[%s] abnormal child process: %s", this->name.string(), strerror(-gzipStatus));
+        ALOGW("[%s] abnormal child process: %s", this->name.c_str(), strerror(-gzipStatus));
         return gzipStatus;
     }
     // Revisit the actual size from gzip result and edit the internal buffer accordingly.
@@ -290,7 +290,7 @@
     FdBuffer buffer;
     err = buffer.read(data->pipe.readFd().get(), this->timeoutMs);
     if (err != NO_ERROR) {
-        ALOGE("[%s] reader failed with error '%s'", this->name.string(), strerror(-err));
+        ALOGE("[%s] reader failed with error '%s'", this->name.c_str(), strerror(-err));
     }
 
     // If the worker side is finished, then return its error (which may overwrite
@@ -300,7 +300,7 @@
         data->pipe.close();
         if (data->workerError != NO_ERROR) {
             err = data->workerError;
-            ALOGE("[%s] worker failed with error '%s'", this->name.string(), strerror(-err));
+            ALOGE("[%s] worker failed with error '%s'", this->name.c_str(), strerror(-err));
         }
         workerDone = data->workerDone;
     }
@@ -309,17 +309,17 @@
     if (err != NO_ERROR) {
         char errMsg[128];
         snprintf(errMsg, 128, "[%s] failed with error '%s'",
-            this->name.string(), strerror(-err));
+            this->name.c_str(), strerror(-err));
         writer->error(this, err, "WorkerThreadSection failed.");
         return NO_ERROR;
     }
     if (buffer.truncated()) {
-        ALOGW("[%s] too large, truncating", this->name.string());
+        ALOGW("[%s] too large, truncating", this->name.c_str());
         // Do not write a truncated section. It won't pass through the PrivacyFilter.
         return NO_ERROR;
     }
     if (!workerDone || buffer.timedOut()) {
-        ALOGW("[%s] timed out", this->name.string());
+        ALOGW("[%s] timed out", this->name.c_str());
         return NO_ERROR;
     }
 
@@ -360,18 +360,18 @@
     Fpipe ihPipe;
 
     if (!cmdPipe.init() || !ihPipe.init()) {
-        ALOGW("[%s] failed to setup pipes", this->name.string());
+        ALOGW("[%s] failed to setup pipes", this->name.c_str());
         return -errno;
     }
 
     pid_t cmdPid = fork_execute_cmd((char* const*)mCommand, NULL, &cmdPipe);
     if (cmdPid == -1) {
-        ALOGW("[%s] failed to fork", this->name.string());
+        ALOGW("[%s] failed to fork", this->name.c_str());
         return -errno;
     }
     pid_t ihPid = fork_execute_incident_helper(this->id, &cmdPipe, &ihPipe);
     if (ihPid == -1) {
-        ALOGW("[%s] failed to fork", this->name.string());
+        ALOGW("[%s] failed to fork", this->name.c_str());
         return -errno;
     }
 
@@ -381,7 +381,7 @@
     writer->setSectionStats(buffer);
     if (readStatus != NO_ERROR || buffer.timedOut()) {
         ALOGW("[%s] failed to read data from incident helper: %s, timedout: %s",
-              this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+              this->name.c_str(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
         kill_child(cmdPid);
         kill_child(ihPid);
         return readStatus;
@@ -393,7 +393,7 @@
     status_t ihStatus = wait_child(ihPid);
     if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
         ALOGW("[%s] abnormal child processes, return status: command: %s, incident helper: %s",
-              this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
+              this->name.c_str(), strerror(-cmdStatus), strerror(-ihStatus));
         // Not a fatal error.
         return NO_ERROR;
     }
@@ -428,7 +428,7 @@
     sp<IBinder> service = defaultServiceManager()->checkService(mService);
 
     if (service == NULL) {
-        ALOGW("DumpsysSection: Can't lookup service: %s", String8(mService).string());
+        ALOGW("DumpsysSection: Can't lookup service: %s", String8(mService).c_str());
         return NAME_NOT_FOUND;
     }
 
@@ -463,14 +463,14 @@
     // checkService won't wait for the service to show up like getService will.
     sp<IBinder> service = defaultServiceManager()->checkService(mService);
     if (service == NULL) {
-        ALOGW("TextDumpsysSection: Can't lookup service: %s", String8(mService).string());
+        ALOGW("TextDumpsysSection: Can't lookup service: %s", String8(mService).c_str());
         return NAME_NOT_FOUND;
     }
 
     // Create pipe
     Fpipe dumpPipe;
     if (!dumpPipe.init()) {
-        ALOGW("[%s] failed to setup pipe", this->name.string());
+        ALOGW("[%s] failed to setup pipe", this->name.c_str());
         return -errno;
     }
 
@@ -482,7 +482,7 @@
         signal(SIGPIPE, sigpipe_handler);
         status_t err = service->dump(write_fd.get(), this->mArgs);
         if (err != OK) {
-            ALOGW("[%s] dump thread failed. Error: %s", this->name.string(), strerror(-err));
+            ALOGW("[%s] dump thread failed. Error: %s", this->name.c_str(), strerror(-err));
         }
         write_fd.reset();
     });
@@ -490,7 +490,7 @@
     // Collect dump content
     FdBuffer buffer;
     ProtoOutputStream proto;
-    proto.write(TextDumpProto::COMMAND, std::string(name.string()));
+    proto.write(TextDumpProto::COMMAND, std::string(name.c_str()));
     proto.write(TextDumpProto::DUMP_DURATION_NS, int64_t(Nanotime() - start));
     buffer.write(proto.data());
 
@@ -504,7 +504,7 @@
     dumpPipe.readFd().reset();
     writer->setSectionStats(buffer);
     if (readStatus != OK || buffer.timedOut()) {
-        ALOGW("[%s] failed to read from dumpsys: %s, timedout: %s", this->name.string(),
+        ALOGW("[%s] failed to read from dumpsys: %s, timedout: %s", this->name.c_str(),
               strerror(-readStatus), buffer.timedOut() ? "true" : "false");
         worker.detach();
         return readStatus;
@@ -579,7 +579,7 @@
     // Hence forking a new process to prevent memory fragmentation.
     pid_t pid = fork();
     if (pid < 0) {
-        ALOGW("[%s] failed to fork", this->name.string());
+        ALOGW("[%s] failed to fork", this->name.c_str());
         return errno;
     }
     if (pid > 0) {
@@ -593,7 +593,7 @@
             android_logger_list_free);
 
     if (android_logger_open(loggers.get(), mLogID) == NULL) {
-        ALOGE("[%s] Can't get logger.", this->name.string());
+        ALOGE("[%s] Can't get logger.", this->name.c_str());
         _exit(EXIT_FAILURE);
     }
 
@@ -610,7 +610,7 @@
         // status = -EAGAIN, graceful indication for ANDRODI_LOG_NONBLOCK that this is the end.
         if (status <= 0) {
             if (status != -EAGAIN) {
-                ALOGW("[%s] fails to read a log_msg.\n", this->name.string());
+                ALOGW("[%s] fails to read a log_msg.\n", this->name.c_str());
                 err = -status;
             }
             break;
@@ -680,7 +680,7 @@
             AndroidLogEntry entry;
             status = android_log_processLogBuffer(&msg.entry, &entry);
             if (status != OK) {
-                ALOGW("[%s] fails to process to an entry.\n", this->name.string());
+                ALOGW("[%s] fails to process to an entry.\n", this->name.c_str());
                 err = status;
                 break;
             }
@@ -702,7 +702,7 @@
         }
         if (!proto.flush(pipeWriteFd.get())) {
             if (errno == EPIPE) {
-                ALOGW("[%s] wrote to a broken pipe\n", this->name.string());
+                ALOGW("[%s] wrote to a broken pipe\n", this->name.c_str());
             }
             err = errno;
             break;
@@ -757,7 +757,7 @@
         }
         ssize_t exe_name_len = readlink(link_name, exe_name, EXE_NAME_LEN);
         if (exe_name_len < 0 || exe_name_len >= EXE_NAME_LEN) {
-            ALOGE("[%s] Can't read '%s': %s", name.string(), link_name, strerror(errno));
+            ALOGE("[%s] Can't read '%s': %s", name.c_str(), link_name, strerror(errno));
             continue;
         }
         // readlink(2) does not put a null terminator at the end
@@ -788,7 +788,7 @@
 
         Fpipe dumpPipe;
         if (!dumpPipe.init()) {
-            ALOGW("[%s] failed to setup dump pipe", this->name.string());
+            ALOGW("[%s] failed to setup dump pipe", this->name.c_str());
             err = -errno;
             break;
         }
@@ -822,12 +822,12 @@
         // Wait on the child to avoid it becoming a zombie process.
         status_t cStatus = wait_child(child);
         if (err != NO_ERROR) {
-            ALOGW("[%s] failed to read stack dump: %d", this->name.string(), err);
+            ALOGW("[%s] failed to read stack dump: %d", this->name.c_str(), err);
             dumpPipe.readFd().reset();
             break;
         }
         if (cStatus != NO_ERROR) {
-            ALOGE("[%s] child had an issue: %s\n", this->name.string(), strerror(-cStatus));
+            ALOGE("[%s] child had an issue: %s\n", this->name.c_str(), strerror(-cStatus));
         }
 
         // Resize dump buffer
@@ -852,7 +852,7 @@
         dumpPipe.readFd().reset();
         if (!proto.flush(pipeWriteFd.get())) {
             if (errno == EPIPE) {
-                ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+                ALOGE("[%s] wrote to a broken pipe\n", this->name.c_str());
             }
             err = errno;
             break;
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 7d20a74..6b2fb8e 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -62,8 +62,8 @@
             continue;
         }
         String8 filename = dirbase + entry->d_name;
-        if (stat(filename.string(), &st) != 0) {
-            ALOGE("Unable to stat file %s", filename.string());
+        if (stat(filename.c_str(), &st) != 0) {
+            ALOGE("Unable to stat file %s", filename.c_str());
             continue;
         }
         if (!S_ISREG(st.st_mode)) {
@@ -88,7 +88,7 @@
     // Remove files until we're under our limits.
     for (std::vector<std::pair<String8, struct stat>>::iterator it = files.begin();
          it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
-        remove(it->first.string());
+        remove(it->first.c_str());
         totalSize -= it->second.st_size;
         totalCount--;
     }
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 214b12c..0351a00 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -12713,7 +12713,6 @@
 com.android.internal.util.LatencyTracker$Action
 com.android.internal.util.LatencyTracker$ActionProperties
 com.android.internal.util.LatencyTracker$FrameworkStatsLogEvent
-com.android.internal.util.LatencyTracker$SLatencyTrackerHolder
 com.android.internal.util.LatencyTracker$Session$$ExternalSyntheticLambda0
 com.android.internal.util.LatencyTracker$Session
 com.android.internal.util.LatencyTracker
diff --git a/core/api/current.txt b/core/api/current.txt
index bcb21e5..0e5a515 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9681,14 +9681,24 @@
   public final class VirtualDevice implements android.os.Parcelable {
     method public int describeContents();
     method public int getDeviceId();
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @NonNull public int[] getDisplayIds();
     method @Nullable public String getName();
     method @Nullable public String getPersistentDeviceId();
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public boolean hasCustomSensorSupport();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR;
   }
 
   public final class VirtualDeviceManager {
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int);
     method @NonNull public java.util.List<android.companion.virtual.VirtualDevice> getVirtualDevices();
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+    method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+  }
+
+  @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public static interface VirtualDeviceManager.VirtualDeviceListener {
+    method public default void onVirtualDeviceClosed(int);
+    method public default void onVirtualDeviceCreated(int);
   }
 
 }
@@ -10560,6 +10570,7 @@
   public final class ContextParams {
     method @Nullable public String getAttributionTag();
     method @Nullable public android.content.AttributionSource getNextAttributionSource();
+    method @NonNull public boolean shouldRegisterAttributionSource();
   }
 
   public static final class ContextParams.Builder {
@@ -10568,6 +10579,7 @@
     method @NonNull public android.content.ContextParams build();
     method @NonNull public android.content.ContextParams.Builder setAttributionTag(@Nullable String);
     method @NonNull public android.content.ContextParams.Builder setNextAttributionSource(@Nullable android.content.AttributionSource);
+    method @NonNull public android.content.ContextParams.Builder setShouldRegisterAttributionSource(boolean);
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -20403,513 +20415,6 @@
 
 package android.location {
 
-  public class Address implements android.os.Parcelable {
-    ctor public Address(java.util.Locale);
-    method public void clearLatitude();
-    method public void clearLongitude();
-    method public int describeContents();
-    method public String getAddressLine(int);
-    method public String getAdminArea();
-    method public String getCountryCode();
-    method public String getCountryName();
-    method public android.os.Bundle getExtras();
-    method public String getFeatureName();
-    method public double getLatitude();
-    method public java.util.Locale getLocale();
-    method public String getLocality();
-    method public double getLongitude();
-    method public int getMaxAddressLineIndex();
-    method public String getPhone();
-    method public String getPostalCode();
-    method public String getPremises();
-    method public String getSubAdminArea();
-    method public String getSubLocality();
-    method public String getSubThoroughfare();
-    method public String getThoroughfare();
-    method public String getUrl();
-    method public boolean hasLatitude();
-    method public boolean hasLongitude();
-    method public void setAddressLine(int, String);
-    method public void setAdminArea(String);
-    method public void setCountryCode(String);
-    method public void setCountryName(String);
-    method public void setExtras(android.os.Bundle);
-    method public void setFeatureName(String);
-    method public void setLatitude(double);
-    method public void setLocality(String);
-    method public void setLongitude(double);
-    method public void setPhone(String);
-    method public void setPostalCode(String);
-    method public void setPremises(String);
-    method public void setSubAdminArea(String);
-    method public void setSubLocality(String);
-    method public void setSubThoroughfare(String);
-    method public void setThoroughfare(String);
-    method public void setUrl(String);
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
-  }
-
-  @Deprecated public class Criteria implements android.os.Parcelable {
-    ctor @Deprecated public Criteria();
-    ctor @Deprecated public Criteria(android.location.Criteria);
-    method @Deprecated public int describeContents();
-    method @Deprecated public int getAccuracy();
-    method @Deprecated public int getBearingAccuracy();
-    method @Deprecated public int getHorizontalAccuracy();
-    method @Deprecated public int getPowerRequirement();
-    method @Deprecated public int getSpeedAccuracy();
-    method @Deprecated public int getVerticalAccuracy();
-    method @Deprecated public boolean isAltitudeRequired();
-    method @Deprecated public boolean isBearingRequired();
-    method @Deprecated public boolean isCostAllowed();
-    method @Deprecated public boolean isSpeedRequired();
-    method @Deprecated public void setAccuracy(int);
-    method @Deprecated public void setAltitudeRequired(boolean);
-    method @Deprecated public void setBearingAccuracy(int);
-    method @Deprecated public void setBearingRequired(boolean);
-    method @Deprecated public void setCostAllowed(boolean);
-    method @Deprecated public void setHorizontalAccuracy(int);
-    method @Deprecated public void setPowerRequirement(int);
-    method @Deprecated public void setSpeedAccuracy(int);
-    method @Deprecated public void setSpeedRequired(boolean);
-    method @Deprecated public void setVerticalAccuracy(int);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated public static final int ACCURACY_COARSE = 2; // 0x2
-    field @Deprecated public static final int ACCURACY_FINE = 1; // 0x1
-    field @Deprecated public static final int ACCURACY_HIGH = 3; // 0x3
-    field @Deprecated public static final int ACCURACY_LOW = 1; // 0x1
-    field @Deprecated public static final int ACCURACY_MEDIUM = 2; // 0x2
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR;
-    field @Deprecated public static final int NO_REQUIREMENT = 0; // 0x0
-    field @Deprecated public static final int POWER_HIGH = 3; // 0x3
-    field @Deprecated public static final int POWER_LOW = 1; // 0x1
-    field @Deprecated public static final int POWER_MEDIUM = 2; // 0x2
-  }
-
-  public final class Geocoder {
-    ctor public Geocoder(@NonNull android.content.Context);
-    ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
-    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
-    method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
-    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
-    method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
-    method public static boolean isPresent();
-  }
-
-  public static interface Geocoder.GeocodeListener {
-    method public default void onError(@Nullable String);
-    method public void onGeocode(@NonNull java.util.List<android.location.Address>);
-  }
-
-  public final class GnssAntennaInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz();
-    method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffset getPhaseCenterOffset();
-    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getPhaseCenterVariationCorrections();
-    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getSignalGainCorrections();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR;
-  }
-
-  public static class GnssAntennaInfo.Builder {
-    ctor @Deprecated public GnssAntennaInfo.Builder();
-    ctor public GnssAntennaInfo.Builder(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
-    ctor public GnssAntennaInfo.Builder(@NonNull android.location.GnssAntennaInfo);
-    method @NonNull public android.location.GnssAntennaInfo build();
-    method @NonNull public android.location.GnssAntennaInfo.Builder setCarrierFrequencyMHz(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterOffset(@NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
-    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterVariationCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
-    method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
-  }
-
-  public static interface GnssAntennaInfo.Listener {
-    method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
-  }
-
-  public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.PhaseCenterOffset(double, double, double, double, double, double);
-    method public int describeContents();
-    method @FloatRange public double getXOffsetMm();
-    method @FloatRange public double getXOffsetUncertaintyMm();
-    method @FloatRange public double getYOffsetMm();
-    method @FloatRange public double getYOffsetUncertaintyMm();
-    method @FloatRange public double getZOffsetMm();
-    method @FloatRange public double getZOffsetUncertaintyMm();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffset> CREATOR;
-  }
-
-  public static final class GnssAntennaInfo.SphericalCorrections implements android.os.Parcelable {
-    ctor public GnssAntennaInfo.SphericalCorrections(@NonNull double[][], @NonNull double[][]);
-    method public int describeContents();
-    method @NonNull public double[][] getCorrectionUncertaintiesArray();
-    method @NonNull public double[][] getCorrectionsArray();
-    method @FloatRange(from=0.0f, to=180.0f) public double getDeltaPhi();
-    method @FloatRange(from=0.0f, to=360.0f) public double getDeltaTheta();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR;
-  }
-
-  public final class GnssAutomaticGainControl implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=0) public long getCarrierFrequencyHz();
-    method public int getConstellationType();
-    method @FloatRange(from=0xffffd8f0, to=10000) public double getLevelDb();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAutomaticGainControl> CREATOR;
-  }
-
-  public static final class GnssAutomaticGainControl.Builder {
-    ctor public GnssAutomaticGainControl.Builder();
-    ctor public GnssAutomaticGainControl.Builder(@NonNull android.location.GnssAutomaticGainControl);
-    method @NonNull public android.location.GnssAutomaticGainControl build();
-    method @NonNull public android.location.GnssAutomaticGainControl.Builder setCarrierFrequencyHz(@IntRange(from=0) long);
-    method @NonNull public android.location.GnssAutomaticGainControl.Builder setConstellationType(int);
-    method @NonNull public android.location.GnssAutomaticGainControl.Builder setLevelDb(@FloatRange(from=0xffffd8f0, to=10000) double);
-  }
-
-  public final class GnssCapabilities implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public java.util.List<android.location.GnssSignalType> getGnssSignalTypes();
-    method public int hasAccumulatedDeltaRange();
-    method public boolean hasAntennaInfo();
-    method public boolean hasGeofencing();
-    method @Deprecated public boolean hasGnssAntennaInfo();
-    method public boolean hasLowPowerMode();
-    method public boolean hasMeasurementCorrections();
-    method public boolean hasMeasurementCorrectionsExcessPathLength();
-    method public boolean hasMeasurementCorrectionsForDriving();
-    method public boolean hasMeasurementCorrectionsLosSats();
-    method public boolean hasMeasurementCorrectionsReflectingPlane();
-    method public boolean hasMeasurementCorrelationVectors();
-    method public boolean hasMeasurements();
-    method public boolean hasMsa();
-    method public boolean hasMsb();
-    method public boolean hasNavigationMessages();
-    method public boolean hasOnDemandTime();
-    method public boolean hasPowerMultibandAcquisition();
-    method public boolean hasPowerMultibandTracking();
-    method public boolean hasPowerOtherModes();
-    method public boolean hasPowerSinglebandAcquisition();
-    method public boolean hasPowerSinglebandTracking();
-    method public boolean hasPowerTotal();
-    method public boolean hasSatelliteBlocklist();
-    method public boolean hasSatellitePvt();
-    method public boolean hasScheduling();
-    method public boolean hasSingleShotFix();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CAPABILITY_SUPPORTED = 1; // 0x1
-    field public static final int CAPABILITY_UNKNOWN = 0; // 0x0
-    field public static final int CAPABILITY_UNSUPPORTED = 2; // 0x2
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR;
-  }
-
-  public static final class GnssCapabilities.Builder {
-    ctor public GnssCapabilities.Builder();
-    ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities);
-    method @NonNull public android.location.GnssCapabilities build();
-    method @NonNull public android.location.GnssCapabilities.Builder setGnssSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(int);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsForDriving(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrelationVectors(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMsa(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasMsb(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasOnDemandTime(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandAcquisition(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandTracking(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerOtherModes(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandAcquisition(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandTracking(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerTotal(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasScheduling(boolean);
-    method @NonNull public android.location.GnssCapabilities.Builder setHasSingleShotFix(boolean);
-  }
-
-  public final class GnssClock implements android.os.Parcelable {
-    method public int describeContents();
-    method public double getBiasNanos();
-    method @FloatRange(from=0.0f) public double getBiasUncertaintyNanos();
-    method public double getDriftNanosPerSecond();
-    method @FloatRange(from=0.0f) public double getDriftUncertaintyNanosPerSecond();
-    method public long getElapsedRealtimeNanos();
-    method @FloatRange(from=0.0f) public double getElapsedRealtimeUncertaintyNanos();
-    method public long getFullBiasNanos();
-    method public int getHardwareClockDiscontinuityCount();
-    method public int getLeapSecond();
-    method @FloatRange(from=0.0) public double getReferenceCarrierFrequencyHzForIsb();
-    method @NonNull public String getReferenceCodeTypeForIsb();
-    method public int getReferenceConstellationTypeForIsb();
-    method public long getTimeNanos();
-    method @FloatRange(from=0.0f) public double getTimeUncertaintyNanos();
-    method public boolean hasBiasNanos();
-    method public boolean hasBiasUncertaintyNanos();
-    method public boolean hasDriftNanosPerSecond();
-    method public boolean hasDriftUncertaintyNanosPerSecond();
-    method public boolean hasElapsedRealtimeNanos();
-    method public boolean hasElapsedRealtimeUncertaintyNanos();
-    method public boolean hasFullBiasNanos();
-    method public boolean hasLeapSecond();
-    method public boolean hasReferenceCarrierFrequencyHzForIsb();
-    method public boolean hasReferenceCodeTypeForIsb();
-    method public boolean hasReferenceConstellationTypeForIsb();
-    method public boolean hasTimeUncertaintyNanos();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
-  }
-
-  public final class GnssMeasurement implements android.os.Parcelable {
-    method public int describeContents();
-    method public double getAccumulatedDeltaRangeMeters();
-    method public int getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyMeters();
-    method @Deprecated public double getAutomaticGainControlLevelDb();
-    method @FloatRange(from=0, to=63) public double getBasebandCn0DbHz();
-    method @Deprecated public long getCarrierCycles();
-    method public float getCarrierFrequencyHz();
-    method @Deprecated public double getCarrierPhase();
-    method @Deprecated public double getCarrierPhaseUncertainty();
-    method @FloatRange(from=0, to=63) public double getCn0DbHz();
-    method @NonNull public String getCodeType();
-    method public int getConstellationType();
-    method public double getFullInterSignalBiasNanos();
-    method @FloatRange(from=0.0) public double getFullInterSignalBiasUncertaintyNanos();
-    method public int getMultipathIndicator();
-    method public double getPseudorangeRateMetersPerSecond();
-    method public double getPseudorangeRateUncertaintyMetersPerSecond();
-    method public long getReceivedSvTimeNanos();
-    method public long getReceivedSvTimeUncertaintyNanos();
-    method public double getSatelliteInterSignalBiasNanos();
-    method @FloatRange(from=0.0) public double getSatelliteInterSignalBiasUncertaintyNanos();
-    method public double getSnrInDb();
-    method public int getState();
-    method public int getSvid();
-    method public double getTimeOffsetNanos();
-    method @Deprecated public boolean hasAutomaticGainControlLevelDb();
-    method public boolean hasBasebandCn0DbHz();
-    method @Deprecated public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyHz();
-    method @Deprecated public boolean hasCarrierPhase();
-    method @Deprecated public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodeType();
-    method public boolean hasFullInterSignalBiasNanos();
-    method public boolean hasFullInterSignalBiasUncertaintyNanos();
-    method public boolean hasSatelliteInterSignalBiasNanos();
-    method public boolean hasSatelliteInterSignalBiasUncertaintyNanos();
-    method public boolean hasSnrInDb();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final int ADR_STATE_HALF_CYCLE_REPORTED = 16; // 0x10
-    field public static final int ADR_STATE_HALF_CYCLE_RESOLVED = 8; // 0x8
-    field public static final int ADR_STATE_RESET = 2; // 0x2
-    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final int ADR_STATE_VALID = 1; // 0x1
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
-    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000
-    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
-    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
-    field public static final int STATE_BIT_SYNC = 2; // 0x2
-    field public static final int STATE_CODE_LOCK = 1; // 0x1
-    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
-    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
-    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
-    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
-    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
-    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
-    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
-    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
-    field public static final int STATE_TOW_DECODED = 8; // 0x8
-    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
-    field public static final int STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public final class GnssMeasurementRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=0) public int getIntervalMillis();
-    method public boolean isFullTracking();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
-    field public static final int PASSIVE_INTERVAL = 2147483647; // 0x7fffffff
-  }
-
-  public static final class GnssMeasurementRequest.Builder {
-    ctor public GnssMeasurementRequest.Builder();
-    ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
-    method @NonNull public android.location.GnssMeasurementRequest build();
-    method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
-    method @NonNull public android.location.GnssMeasurementRequest.Builder setIntervalMillis(@IntRange(from=0) int);
-  }
-
-  public final class GnssMeasurementsEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public android.location.GnssClock getClock();
-    method @NonNull public java.util.Collection<android.location.GnssAutomaticGainControl> getGnssAutomaticGainControls();
-    method @NonNull public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
-    method public boolean hasIsFullTracking();
-    method public boolean isFullTracking();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-  }
-
-  public static final class GnssMeasurementsEvent.Builder {
-    ctor public GnssMeasurementsEvent.Builder();
-    ctor public GnssMeasurementsEvent.Builder(@NonNull android.location.GnssMeasurementsEvent);
-    method @NonNull public android.location.GnssMeasurementsEvent build();
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder clearIsFullTracking();
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setClock(@NonNull android.location.GnssClock);
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setGnssAutomaticGainControls(@NonNull java.util.Collection<android.location.GnssAutomaticGainControl>);
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setIsFullTracking(boolean);
-    method @NonNull public android.location.GnssMeasurementsEvent.Builder setMeasurements(@NonNull java.util.Collection<android.location.GnssMeasurement>);
-  }
-
-  public abstract static class GnssMeasurementsEvent.Callback {
-    ctor public GnssMeasurementsEvent.Callback();
-    method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
-    method @Deprecated public void onStatusChanged(int);
-    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
-    field @Deprecated public static final int STATUS_NOT_ALLOWED = 3; // 0x3
-    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field @Deprecated public static final int STATUS_READY = 1; // 0x1
-  }
-
-  public final class GnssNavigationMessage implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public byte[] getData();
-    method @IntRange(from=0xffffffff, to=120) public int getMessageId();
-    method public int getStatus();
-    method @IntRange(from=1) public int getSubmessageId();
-    method @IntRange(from=1, to=200) public int getSvid();
-    method public int getType();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final int STATUS_UNKNOWN = 0; // 0x0
-    field public static final int TYPE_BDS_CNAV1 = 1283; // 0x503
-    field public static final int TYPE_BDS_CNAV2 = 1284; // 0x504
-    field public static final int TYPE_BDS_D1 = 1281; // 0x501
-    field public static final int TYPE_BDS_D2 = 1282; // 0x502
-    field public static final int TYPE_GAL_F = 1538; // 0x602
-    field public static final int TYPE_GAL_I = 1537; // 0x601
-    field public static final int TYPE_GLO_L1CA = 769; // 0x301
-    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final int TYPE_GPS_L1CA = 257; // 0x101
-    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final int TYPE_IRN_L5CA = 1793; // 0x701
-    field public static final int TYPE_QZS_L1CA = 1025; // 0x401
-    field public static final int TYPE_SBS = 513; // 0x201
-    field public static final int TYPE_UNKNOWN = 0; // 0x0
-  }
-
-  public abstract static class GnssNavigationMessage.Callback {
-    ctor public GnssNavigationMessage.Callback();
-    method public void onGnssNavigationMessageReceived(android.location.GnssNavigationMessage);
-    method @Deprecated public void onStatusChanged(int);
-    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
-    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field @Deprecated public static final int STATUS_READY = 1; // 0x1
-  }
-
-  public final class GnssSignalType implements android.os.Parcelable {
-    method @NonNull public static android.location.GnssSignalType create(int, @FloatRange(from=0.0f, fromInclusive=false) double, @NonNull String);
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getCarrierFrequencyHz();
-    method @NonNull public String getCodeType();
-    method public int getConstellationType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssSignalType> CREATOR;
-  }
-
-  public final class GnssStatus implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
-    method @FloatRange(from=0, to=63) public float getBasebandCn0DbHz(@IntRange(from=0) int);
-    method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
-    method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
-    method public int getConstellationType(@IntRange(from=0) int);
-    method @FloatRange(from=0xffffffa6, to=90) public float getElevationDegrees(@IntRange(from=0) int);
-    method @IntRange(from=0) public int getSatelliteCount();
-    method @IntRange(from=1, to=206) public int getSvid(@IntRange(from=0) int);
-    method public boolean hasAlmanacData(@IntRange(from=0) int);
-    method public boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
-    method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
-    method public boolean hasEphemerisData(@IntRange(from=0) int);
-    method public boolean usedInFix(@IntRange(from=0) int);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final int CONSTELLATION_GPS = 1; // 0x1
-    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
-    field public static final int CONSTELLATION_QZSS = 4; // 0x4
-    field public static final int CONSTELLATION_SBAS = 2; // 0x2
-    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssStatus> CREATOR;
-  }
-
-  public static final class GnssStatus.Builder {
-    ctor public GnssStatus.Builder();
-    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float, boolean, @FloatRange(from=0, to=63) float);
-    method @NonNull public android.location.GnssStatus build();
-    method @NonNull public android.location.GnssStatus.Builder clearSatellites();
-  }
-
-  public abstract static class GnssStatus.Callback {
-    ctor public GnssStatus.Callback();
-    method public void onFirstFix(int);
-    method public void onSatelliteStatusChanged(@NonNull android.location.GnssStatus);
-    method public void onStarted();
-    method public void onStopped();
-  }
-
-  @Deprecated public final class GpsSatellite {
-    method @Deprecated public float getAzimuth();
-    method @Deprecated public float getElevation();
-    method @Deprecated public int getPrn();
-    method @Deprecated public float getSnr();
-    method @Deprecated public boolean hasAlmanac();
-    method @Deprecated public boolean hasEphemeris();
-    method @Deprecated public boolean usedInFix();
-  }
-
-  @Deprecated public final class GpsStatus {
-    method @Deprecated @NonNull public static android.location.GpsStatus create(@NonNull android.location.GnssStatus, int);
-    method @Deprecated public int getMaxSatellites();
-    method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
-    method @Deprecated public int getTimeToFirstFix();
-    field @Deprecated public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
-    field @Deprecated public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
-    field @Deprecated public static final int GPS_EVENT_STARTED = 1; // 0x1
-    field @Deprecated public static final int GPS_EVENT_STOPPED = 2; // 0x2
-  }
-
-  @Deprecated public static interface GpsStatus.Listener {
-    method @Deprecated public void onGpsStatusChanged(int);
-  }
-
-  @Deprecated public static interface GpsStatus.NmeaListener {
-    method @Deprecated public void onNmeaReceived(long, String);
-  }
-
   public class Location implements android.os.Parcelable {
     ctor public Location(@Nullable String);
     ctor public Location(@NonNull android.location.Location);
@@ -20988,219 +20493,6 @@
     field public static final int FORMAT_SECONDS = 2; // 0x2
   }
 
-  public interface LocationListener {
-    method public default void onFlushComplete(int);
-    method public void onLocationChanged(@NonNull android.location.Location);
-    method public default void onLocationChanged(@NonNull java.util.List<android.location.Location>);
-    method public default void onProviderDisabled(@NonNull String);
-    method public default void onProviderEnabled(@NonNull String);
-    method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
-  }
-
-  public class LocationManager {
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
-    method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
-    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties);
-    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties, @NonNull java.util.Set<java.lang.String>);
-    method @Deprecated public void clearTestProviderEnabled(@NonNull String);
-    method @Deprecated public void clearTestProviderLocation(@NonNull String);
-    method @Deprecated public void clearTestProviderStatus(@NonNull String);
-    method @NonNull public java.util.List<java.lang.String> getAllProviders();
-    method @Deprecated @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
-    method @Nullable public java.util.List<android.location.GnssAntennaInfo> getGnssAntennaInfos();
-    method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
-    method @Nullable public String getGnssHardwareModelName();
-    method public int getGnssYearOfHardware();
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
-    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
-    method @Deprecated @Nullable public android.location.LocationProvider getProvider(@NonNull String);
-    method @Nullable public android.location.provider.ProviderProperties getProviderProperties(@NonNull String);
-    method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
-    method @Deprecated @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
-    method public boolean hasProvider(@NonNull String);
-    method public boolean isLocationEnabled();
-    method public boolean isProviderEnabled(@NonNull String);
-    method public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
-    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
-    method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
-    method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
-    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
-    method public void removeTestProvider(@NonNull String);
-    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
-    method public void removeUpdates(@NonNull android.app.PendingIntent);
-    method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
-    method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
-    method public boolean sendExtraCommand(@NonNull String, @NonNull String, @Nullable android.os.Bundle);
-    method public void setTestProviderEnabled(@NonNull String, boolean);
-    method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
-    method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
-    method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
-    method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
-    method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
-    method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
-    field public static final String ACTION_GNSS_CAPABILITIES_CHANGED = "android.location.action.GNSS_CAPABILITIES_CHANGED";
-    field public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
-    field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
-    field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
-    field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
-    field public static final String FUSED_PROVIDER = "fused";
-    field public static final String GPS_PROVIDER = "gps";
-    field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
-    field public static final String KEY_LOCATIONS = "locations";
-    field public static final String KEY_LOCATION_CHANGED = "location";
-    field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
-    field public static final String KEY_PROXIMITY_ENTERING = "entering";
-    field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
-    field public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
-    field public static final String NETWORK_PROVIDER = "network";
-    field public static final String PASSIVE_PROVIDER = "passive";
-    field public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
-  }
-
-  @Deprecated public class LocationProvider {
-    method @Deprecated public int getAccuracy();
-    method @Deprecated public String getName();
-    method @Deprecated public int getPowerRequirement();
-    method @Deprecated public boolean hasMonetaryCost();
-    method @Deprecated public boolean meetsCriteria(android.location.Criteria);
-    method @Deprecated public boolean requiresCell();
-    method @Deprecated public boolean requiresNetwork();
-    method @Deprecated public boolean requiresSatellite();
-    method @Deprecated public boolean supportsAltitude();
-    method @Deprecated public boolean supportsBearing();
-    method @Deprecated public boolean supportsSpeed();
-    field @Deprecated public static final int AVAILABLE = 2; // 0x2
-    field @Deprecated public static final int OUT_OF_SERVICE = 0; // 0x0
-    field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
-  }
-
-  public final class LocationRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=1) public long getDurationMillis();
-    method @IntRange(from=0) public long getIntervalMillis();
-    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
-    method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
-    method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
-    method @IntRange(from=0) public long getMinUpdateIntervalMillis();
-    method public int getQuality();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
-    field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
-    field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
-    field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
-    field public static final int QUALITY_LOW_POWER = 104; // 0x68
-  }
-
-  public static final class LocationRequest.Builder {
-    ctor public LocationRequest.Builder(long);
-    ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
-    method @NonNull public android.location.LocationRequest build();
-    method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
-    method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
-    method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
-    method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
-    method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.LocationRequest.Builder setQuality(int);
-  }
-
-  public interface OnNmeaMessageListener {
-    method public void onNmeaMessage(String, long);
-  }
-
-  public abstract class SettingInjectorService extends android.app.Service {
-    ctor public SettingInjectorService(String);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract boolean onGetEnabled();
-    method protected abstract String onGetSummary();
-    method public final void onStart(android.content.Intent, int);
-    method public final int onStartCommand(android.content.Intent, int, int);
-    method public static final void refreshSettings(@NonNull android.content.Context);
-    field public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
-    field public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
-    field public static final String ATTRIBUTES_NAME = "injected-location-setting";
-    field public static final String META_DATA_NAME = "android.location.SettingInjectorService";
-  }
-
-}
-
-package android.location.altitude {
-
-  public final class AltitudeConverter {
-    ctor public AltitudeConverter();
-    method @WorkerThread public void addMslAltitudeToLocation(@NonNull android.content.Context, @NonNull android.location.Location) throws java.io.IOException;
-  }
-
-}
-
-package android.location.provider {
-
-  public final class ProviderProperties implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getAccuracy();
-    method public int getPowerUsage();
-    method public boolean hasAltitudeSupport();
-    method public boolean hasBearingSupport();
-    method public boolean hasCellRequirement();
-    method public boolean hasMonetaryCost();
-    method public boolean hasNetworkRequirement();
-    method public boolean hasSatelliteRequirement();
-    method public boolean hasSpeedSupport();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int ACCURACY_COARSE = 2; // 0x2
-    field public static final int ACCURACY_FINE = 1; // 0x1
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderProperties> CREATOR;
-    field public static final int POWER_USAGE_HIGH = 3; // 0x3
-    field public static final int POWER_USAGE_LOW = 1; // 0x1
-    field public static final int POWER_USAGE_MEDIUM = 2; // 0x2
-  }
-
-  public static final class ProviderProperties.Builder {
-    ctor public ProviderProperties.Builder();
-    ctor public ProviderProperties.Builder(@NonNull android.location.provider.ProviderProperties);
-    method @NonNull public android.location.provider.ProviderProperties build();
-    method @NonNull public android.location.provider.ProviderProperties.Builder setAccuracy(int);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasAltitudeSupport(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasBearingSupport(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasCellRequirement(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasMonetaryCost(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasNetworkRequirement(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSatelliteRequirement(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSpeedSupport(boolean);
-    method @NonNull public android.location.provider.ProviderProperties.Builder setPowerUsage(int);
-  }
-
 }
 
 package android.media {
@@ -39349,8 +38641,10 @@
   }
 
   public final class FileIntegrityManager {
+    method @FlaggedApi(Flags.FLAG_FSVERITY_API) @Nullable public byte[] getFsVerityDigest(@NonNull java.io.File) throws java.io.IOException;
     method public boolean isApkVeritySupported();
     method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException;
+    method @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsVerity(@NonNull java.io.File) throws java.io.IOException;
   }
 
   public final class KeyChain {
@@ -42269,7 +41563,7 @@
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
-    field public static final int PROPERTY_IS_TRANSACTIONAL = 32768; // 0x8000
+    field @FlaggedApi(Flags.FLAG_VOIP_APP_ACTIONS_SUPPORT) public static final int PROPERTY_IS_TRANSACTIONAL = 32768; // 0x8000
     field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
     field public static final int PROPERTY_RTT = 1024; // 0x400
     field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b1feb41..3de7748 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -6,7 +6,9 @@
     field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
     field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
     field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
+    field public static final String MANAGE_REMOTE_AUTH = "android.permission.MANAGE_REMOTE_AUTH";
     field public static final String USE_COMPANION_TRANSPORTS = "android.permission.USE_COMPANION_TRANSPORTS";
+    field public static final String USE_REMOTE_AUTH = "android.permission.USE_REMOTE_AUTH";
   }
 
 }
@@ -184,16 +186,6 @@
 
 }
 
-package android.location {
-
-  public class LocationManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public boolean injectLocation(@NonNull android.location.Location);
-    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public boolean isAutomotiveGnssSuspended();
-    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public void setAutomotiveGnssSuspended(boolean);
-  }
-
-}
-
 package android.media {
 
   public class AudioManager {
@@ -527,6 +519,7 @@
   public static final class Settings.Config extends android.provider.Settings.NameValueTable {
     method @RequiresPermission(android.Manifest.permission.MONITOR_DEVICE_CONFIG_ACCESS) public static void clearMonitorCallback(@NonNull android.content.ContentResolver);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean deleteString(@NonNull String, @NonNull String);
+    method @NonNull public static java.util.Map<java.lang.String,java.lang.String> getAllStrings();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static java.util.Map<java.lang.String,java.lang.String> getStrings(@NonNull String, @NonNull java.util.List<java.lang.String>);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static int getSyncDisabledMode();
diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt
index 27436ce..471745a 100644
--- a/core/api/module-lib-lint-baseline.txt
+++ b/core/api/module-lib-lint-baseline.txt
@@ -17,18 +17,6 @@
     SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpBack) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String):
     SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.PackageItemInfo.dumpFront) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioManager#abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes):
     SAM-compatible parameters (such as parameter 1, "l", in android.media.AudioManager.abandonAudioFocus) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes, int, int):
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2137f47..ff44a1b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3213,6 +3213,7 @@
     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 removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
     method public void removeSoundEffectListener(@NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
+    method @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY) @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setDevicePolicy(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);
   }
@@ -3546,6 +3547,7 @@
     field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
     field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
     field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
+    field public static final String ACTION_UNARCHIVE_PACKAGE = "android.intent.action.UNARCHIVE_PACKAGE";
     field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
     field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
     field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
@@ -3793,6 +3795,17 @@
     field @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public static final int FLAG_GET_PERSONS_DATA = 2048; // 0x800
   }
 
+  public class PackageArchiver {
+    method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void requestArchive(@NonNull String, @NonNull android.content.IntentSender) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public void requestUnarchive(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    field public static final String EXTRA_UNARCHIVE_ALL_USERS = "android.content.pm.extra.UNARCHIVE_ALL_USERS";
+    field public static final String EXTRA_UNARCHIVE_PACKAGE_NAME = "android.content.pm.extra.UNARCHIVE_PACKAGE_NAME";
+  }
+
+  public class PackageInfo implements android.os.Parcelable {
+    field public boolean isArchived;
+  }
+
   public class PackageInstaller {
     method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull java.io.File, int) throws android.content.pm.PackageInstaller.PackageParsingException;
     method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull android.os.ParcelFileDescriptor, @Nullable String, int) throws android.content.pm.PackageInstaller.PackageParsingException;
@@ -3890,6 +3903,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
     method @Deprecated @NonNull public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(@NonNull String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(@NonNull String, int);
+    method @NonNull public android.content.pm.PackageArchiver getPackageArchiver();
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public int getPackageUidAsUser(@NonNull String, @NonNull android.content.pm.PackageManager.PackageInfoFlags, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
@@ -4011,6 +4025,7 @@
     field @Deprecated public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
     field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ANY_USER = 4194304; // 0x400000
+    field public static final long MATCH_ARCHIVED_PACKAGES = 4294967296L; // 0x100000000L
     field public static final int MATCH_CLONE_PROFILE = 536870912; // 0x20000000
     field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
     field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
@@ -6167,653 +6182,12 @@
 
 package android.location {
 
-  public abstract class BatchedLocationCallback {
-    ctor public BatchedLocationCallback();
-    method public void onLocationBatch(java.util.List<android.location.Location>);
-  }
-
-  public final class CorrelationVector implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond();
-    method @NonNull public int[] getMagnitude();
-    method @FloatRange(from=0.0f) public double getSamplingStartMeters();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.CorrelationVector> CREATOR;
-  }
-
-  public static final class CorrelationVector.Builder {
-    ctor public CorrelationVector.Builder();
-    method @NonNull public android.location.CorrelationVector build();
-    method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]);
-    method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double);
-  }
-
-  public final class Country implements android.os.Parcelable {
-    ctor public Country(@NonNull String, int);
-    method public int describeContents();
-    method @NonNull public String getCountryCode();
-    method public int getSource();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final int COUNTRY_SOURCE_LOCALE = 3; // 0x3
-    field public static final int COUNTRY_SOURCE_LOCATION = 1; // 0x1
-    field public static final int COUNTRY_SOURCE_NETWORK = 0; // 0x0
-    field public static final int COUNTRY_SOURCE_SIM = 2; // 0x2
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.Country> CREATOR;
-  }
-
-  public class CountryDetector {
-    method public void registerCountryDetectorCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Country>);
-    method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer<android.location.Country>);
-  }
-
-  public final class GnssCapabilities implements android.os.Parcelable {
-    method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane();
-    method @Deprecated public boolean hasNavMessages();
-    method @Deprecated public boolean hasSatelliteBlacklist();
-  }
-
-  public final class GnssExcessPathInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f) public float getAttenuationDb();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
-    method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
-    method public boolean hasAttenuation();
-    method public boolean hasExcessPathLength();
-    method public boolean hasExcessPathLengthUncertainty();
-    method public boolean hasReflectingPlane();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
-  }
-
-  public static final class GnssExcessPathInfo.Builder {
-    ctor public GnssExcessPathInfo.Builder();
-    method @NonNull public android.location.GnssExcessPathInfo build();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
-  }
-
-  public final class GnssMeasurement implements android.os.Parcelable {
-    method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
-    method @Nullable public android.location.SatellitePvt getSatellitePvt();
-    method public boolean hasCorrelationVectors();
-    method public boolean hasSatellitePvt();
-  }
-
-  public final class GnssMeasurementCorrections implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
-    method @FloatRange(from=0.0f, to=360.0f) public float getEnvironmentBearingDegrees();
-    method @FloatRange(from=0.0f, to=180.0f) public float getEnvironmentBearingUncertaintyDegrees();
-    method @FloatRange(from=0.0f) public double getHorizontalPositionUncertaintyMeters();
-    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
-    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
-    method @NonNull public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList();
-    method @IntRange(from=0) public long getToaGpsNanosecondsOfWeek();
-    method @FloatRange(from=0.0f) public double getVerticalPositionUncertaintyMeters();
-    method public boolean hasEnvironmentBearing();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
-  }
-
-  public static final class GnssMeasurementCorrections.Builder {
-    ctor public GnssMeasurementCorrections.Builder();
-    method @NonNull public android.location.GnssMeasurementCorrections build();
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingDegrees(@FloatRange(from=0.0f, to=360.0f) float);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingUncertaintyDegrees(@FloatRange(from=0.0f, to=180.0f) float);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setSingleSatelliteCorrectionList(@NonNull java.util.List<android.location.GnssSingleSatCorrection>);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(@IntRange(from=0) long);
-    method @NonNull public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
-  }
-
-  public final class GnssMeasurementRequest implements android.os.Parcelable {
-    method @NonNull public android.os.WorkSource getWorkSource();
-    method public boolean isCorrelationVectorOutputsEnabled();
-  }
-
-  public static final class GnssMeasurementRequest.Builder {
-    method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
-  }
-
-  public final class GnssReflectingPlane implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
-    method @FloatRange(from=0.0f, to=360.0f) public double getAzimuthDegrees();
-    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
-    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.location.GnssReflectingPlane> CREATOR;
-  }
-
-  public static final class GnssReflectingPlane.Builder {
-    ctor public GnssReflectingPlane.Builder();
-    method @NonNull public android.location.GnssReflectingPlane build();
-    method @NonNull public android.location.GnssReflectingPlane.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
-    method @NonNull public android.location.GnssReflectingPlane.Builder setAzimuthDegrees(@FloatRange(from=0.0f, to=360.0f) double);
-    method @NonNull public android.location.GnssReflectingPlane.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
-    method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
-  }
-
-  public final class GnssRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method public boolean isFullTracking();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR;
-  }
-
-  public static final class GnssRequest.Builder {
-    ctor public GnssRequest.Builder();
-    ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest);
-    method @NonNull public android.location.GnssRequest build();
-    method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean);
-  }
-
-  public final class GnssSingleSatCorrection implements android.os.Parcelable {
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
-    method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
-    method public int getConstellationType();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
-    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
-    method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
-    method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
-    method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
-    method @IntRange(from=0) public int getSatelliteId();
-    method public boolean hasCombinedAttenuation();
-    method public boolean hasExcessPathLength();
-    method public boolean hasExcessPathLengthUncertainty();
-    method @Deprecated public boolean hasReflectingPlane();
-    method public boolean hasValidSatelliteLineOfSight();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
-  }
-
-  public static final class GnssSingleSatCorrection.Builder {
-    ctor public GnssSingleSatCorrection.Builder();
-    method @NonNull public android.location.GnssSingleSatCorrection build();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
-    method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
-    method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
-  }
-
-  @Deprecated public class GpsClock implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated public double getBiasInNs();
-    method @Deprecated public double getBiasUncertaintyInNs();
-    method @Deprecated public double getDriftInNsPerSec();
-    method @Deprecated public double getDriftUncertaintyInNsPerSec();
-    method @Deprecated public long getFullBiasInNs();
-    method @Deprecated public short getLeapSecond();
-    method @Deprecated public long getTimeInNs();
-    method @Deprecated public double getTimeUncertaintyInNs();
-    method @Deprecated public byte getType();
-    method @Deprecated public boolean hasBiasInNs();
-    method @Deprecated public boolean hasBiasUncertaintyInNs();
-    method @Deprecated public boolean hasDriftInNsPerSec();
-    method @Deprecated public boolean hasDriftUncertaintyInNsPerSec();
-    method @Deprecated public boolean hasFullBiasInNs();
-    method @Deprecated public boolean hasLeapSecond();
-    method @Deprecated public boolean hasTimeUncertaintyInNs();
-    method @Deprecated public void reset();
-    method @Deprecated public void resetBiasInNs();
-    method @Deprecated public void resetBiasUncertaintyInNs();
-    method @Deprecated public void resetDriftInNsPerSec();
-    method @Deprecated public void resetDriftUncertaintyInNsPerSec();
-    method @Deprecated public void resetFullBiasInNs();
-    method @Deprecated public void resetLeapSecond();
-    method @Deprecated public void resetTimeUncertaintyInNs();
-    method @Deprecated public void set(android.location.GpsClock);
-    method @Deprecated public void setBiasInNs(double);
-    method @Deprecated public void setBiasUncertaintyInNs(double);
-    method @Deprecated public void setDriftInNsPerSec(double);
-    method @Deprecated public void setDriftUncertaintyInNsPerSec(double);
-    method @Deprecated public void setFullBiasInNs(long);
-    method @Deprecated public void setLeapSecond(short);
-    method @Deprecated public void setTimeInNs(long);
-    method @Deprecated public void setTimeUncertaintyInNs(double);
-    method @Deprecated public void setType(byte);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
-    field @Deprecated public static final byte TYPE_GPS_TIME = 2; // 0x2
-    field @Deprecated public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
-    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
-  }
-
-  @Deprecated public class GpsMeasurement implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated public double getAccumulatedDeltaRangeInMeters();
-    method @Deprecated public short getAccumulatedDeltaRangeState();
-    method @Deprecated public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method @Deprecated public double getAzimuthInDeg();
-    method @Deprecated public double getAzimuthUncertaintyInDeg();
-    method @Deprecated public int getBitNumber();
-    method @Deprecated public long getCarrierCycles();
-    method @Deprecated public float getCarrierFrequencyInHz();
-    method @Deprecated public double getCarrierPhase();
-    method @Deprecated public double getCarrierPhaseUncertainty();
-    method @Deprecated public double getCn0InDbHz();
-    method @Deprecated public double getCodePhaseInChips();
-    method @Deprecated public double getCodePhaseUncertaintyInChips();
-    method @Deprecated public double getDopplerShiftInHz();
-    method @Deprecated public double getDopplerShiftUncertaintyInHz();
-    method @Deprecated public double getElevationInDeg();
-    method @Deprecated public double getElevationUncertaintyInDeg();
-    method @Deprecated public byte getLossOfLock();
-    method @Deprecated public byte getMultipathIndicator();
-    method @Deprecated public byte getPrn();
-    method @Deprecated public double getPseudorangeInMeters();
-    method @Deprecated public double getPseudorangeRateInMetersPerSec();
-    method @Deprecated public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method @Deprecated public double getPseudorangeUncertaintyInMeters();
-    method @Deprecated public long getReceivedGpsTowInNs();
-    method @Deprecated public long getReceivedGpsTowUncertaintyInNs();
-    method @Deprecated public double getSnrInDb();
-    method @Deprecated public short getState();
-    method @Deprecated public short getTimeFromLastBitInMs();
-    method @Deprecated public double getTimeOffsetInNs();
-    method @Deprecated public boolean hasAzimuthInDeg();
-    method @Deprecated public boolean hasAzimuthUncertaintyInDeg();
-    method @Deprecated public boolean hasBitNumber();
-    method @Deprecated public boolean hasCarrierCycles();
-    method @Deprecated public boolean hasCarrierFrequencyInHz();
-    method @Deprecated public boolean hasCarrierPhase();
-    method @Deprecated public boolean hasCarrierPhaseUncertainty();
-    method @Deprecated public boolean hasCodePhaseInChips();
-    method @Deprecated public boolean hasCodePhaseUncertaintyInChips();
-    method @Deprecated public boolean hasDopplerShiftInHz();
-    method @Deprecated public boolean hasDopplerShiftUncertaintyInHz();
-    method @Deprecated public boolean hasElevationInDeg();
-    method @Deprecated public boolean hasElevationUncertaintyInDeg();
-    method @Deprecated public boolean hasPseudorangeInMeters();
-    method @Deprecated public boolean hasPseudorangeUncertaintyInMeters();
-    method @Deprecated public boolean hasSnrInDb();
-    method @Deprecated public boolean hasTimeFromLastBitInMs();
-    method @Deprecated public boolean isPseudorangeRateCorrected();
-    method @Deprecated public boolean isUsedInFix();
-    method @Deprecated public void reset();
-    method @Deprecated public void resetAzimuthInDeg();
-    method @Deprecated public void resetAzimuthUncertaintyInDeg();
-    method @Deprecated public void resetBitNumber();
-    method @Deprecated public void resetCarrierCycles();
-    method @Deprecated public void resetCarrierFrequencyInHz();
-    method @Deprecated public void resetCarrierPhase();
-    method @Deprecated public void resetCarrierPhaseUncertainty();
-    method @Deprecated public void resetCodePhaseInChips();
-    method @Deprecated public void resetCodePhaseUncertaintyInChips();
-    method @Deprecated public void resetDopplerShiftInHz();
-    method @Deprecated public void resetDopplerShiftUncertaintyInHz();
-    method @Deprecated public void resetElevationInDeg();
-    method @Deprecated public void resetElevationUncertaintyInDeg();
-    method @Deprecated public void resetPseudorangeInMeters();
-    method @Deprecated public void resetPseudorangeUncertaintyInMeters();
-    method @Deprecated public void resetSnrInDb();
-    method @Deprecated public void resetTimeFromLastBitInMs();
-    method @Deprecated public void set(android.location.GpsMeasurement);
-    method @Deprecated public void setAccumulatedDeltaRangeInMeters(double);
-    method @Deprecated public void setAccumulatedDeltaRangeState(short);
-    method @Deprecated public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method @Deprecated public void setAzimuthInDeg(double);
-    method @Deprecated public void setAzimuthUncertaintyInDeg(double);
-    method @Deprecated public void setBitNumber(int);
-    method @Deprecated public void setCarrierCycles(long);
-    method @Deprecated public void setCarrierFrequencyInHz(float);
-    method @Deprecated public void setCarrierPhase(double);
-    method @Deprecated public void setCarrierPhaseUncertainty(double);
-    method @Deprecated public void setCn0InDbHz(double);
-    method @Deprecated public void setCodePhaseInChips(double);
-    method @Deprecated public void setCodePhaseUncertaintyInChips(double);
-    method @Deprecated public void setDopplerShiftInHz(double);
-    method @Deprecated public void setDopplerShiftUncertaintyInHz(double);
-    method @Deprecated public void setElevationInDeg(double);
-    method @Deprecated public void setElevationUncertaintyInDeg(double);
-    method @Deprecated public void setLossOfLock(byte);
-    method @Deprecated public void setMultipathIndicator(byte);
-    method @Deprecated public void setPrn(byte);
-    method @Deprecated public void setPseudorangeInMeters(double);
-    method @Deprecated public void setPseudorangeRateInMetersPerSec(double);
-    method @Deprecated public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method @Deprecated public void setPseudorangeUncertaintyInMeters(double);
-    method @Deprecated public void setReceivedGpsTowInNs(long);
-    method @Deprecated public void setReceivedGpsTowUncertaintyInNs(long);
-    method @Deprecated public void setSnrInDb(double);
-    method @Deprecated public void setState(short);
-    method @Deprecated public void setTimeFromLastBitInMs(short);
-    method @Deprecated public void setTimeOffsetInNs(double);
-    method @Deprecated public void setUsedInFix(boolean);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field @Deprecated public static final short ADR_STATE_RESET = 2; // 0x2
-    field @Deprecated public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final short ADR_STATE_VALID = 1; // 0x1
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
-    field @Deprecated public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field @Deprecated public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field @Deprecated public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field @Deprecated public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field @Deprecated public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final short STATE_BIT_SYNC = 2; // 0x2
-    field @Deprecated public static final short STATE_CODE_LOCK = 1; // 0x1
-    field @Deprecated public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field @Deprecated public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field @Deprecated public static final short STATE_TOW_DECODED = 8; // 0x8
-    field @Deprecated public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  @Deprecated public class GpsMeasurementsEvent implements android.os.Parcelable {
-    ctor @Deprecated public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public android.location.GpsClock getClock();
-    method @Deprecated @NonNull public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
-    field @Deprecated public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
-    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
-    field @Deprecated public static final int STATUS_READY = 1; // 0x1
-  }
-
-  @Deprecated public static interface GpsMeasurementsEvent.Listener {
-    method @Deprecated public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
-    method @Deprecated public void onStatusChanged(int);
-  }
-
-  @Deprecated public class GpsNavigationMessage implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public byte[] getData();
-    method @Deprecated public short getMessageId();
-    method @Deprecated public byte getPrn();
-    method @Deprecated public short getStatus();
-    method @Deprecated public short getSubmessageId();
-    method @Deprecated public byte getType();
-    method @Deprecated public void reset();
-    method @Deprecated public void set(android.location.GpsNavigationMessage);
-    method @Deprecated public void setData(byte[]);
-    method @Deprecated public void setMessageId(short);
-    method @Deprecated public void setPrn(byte);
-    method @Deprecated public void setStatus(short);
-    method @Deprecated public void setSubmessageId(short);
-    method @Deprecated public void setType(byte);
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
-    field @Deprecated public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field @Deprecated public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field @Deprecated public static final short STATUS_UNKNOWN = 0; // 0x0
-    field @Deprecated public static final byte TYPE_CNAV2 = 4; // 0x4
-    field @Deprecated public static final byte TYPE_L1CA = 1; // 0x1
-    field @Deprecated public static final byte TYPE_L2CNAV = 2; // 0x2
-    field @Deprecated public static final byte TYPE_L5CNAV = 3; // 0x3
-    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
-  }
-
-  @Deprecated public class GpsNavigationMessageEvent implements android.os.Parcelable {
-    ctor @Deprecated public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public android.location.GpsNavigationMessage getNavigationMessage();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
-    field @Deprecated public static int STATUS_GPS_LOCATION_DISABLED;
-    field @Deprecated public static int STATUS_NOT_SUPPORTED;
-    field @Deprecated public static int STATUS_READY;
-  }
-
-  @Deprecated public static interface GpsNavigationMessageEvent.Listener {
-    method @Deprecated public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
-    method @Deprecated public void onStatusChanged(int);
-  }
-
-  public final class LastLocationRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method public boolean isAdasGnssBypass();
-    method public boolean isHiddenFromAppOps();
-    method public boolean isLocationSettingsIgnored();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.LastLocationRequest> CREATOR;
-  }
-
-  public static final class LastLocationRequest.Builder {
-    ctor public LastLocationRequest.Builder();
-    ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
-    method @NonNull public android.location.LastLocationRequest build();
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
-  }
-
   public class Location implements android.os.Parcelable {
     method public void makeComplete();
     method @Deprecated public void setIsFromMockProvider(boolean);
     field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
   }
 
-  public class LocationManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
-    method @Nullable public String getExtraLocationControllerPackage();
-    method @Deprecated public int getGnssBatchSize();
-    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String, @NonNull android.location.LastLocationRequest);
-    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
-    method public boolean isAdasGnssLocationEnabled();
-    method public boolean isExtraLocationControllerPackageEnabled();
-    method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
-    method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
-    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void removeProviderRequestChangedListener(@NonNull android.location.provider.ProviderRequest.ChangedListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public void setAdasGnssLocationEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
-    field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
-    field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
-    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
-  }
-
-  public final class LocationRequest implements android.os.Parcelable {
-    method @Deprecated @NonNull public static android.location.LocationRequest create();
-    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
-    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
-    method @Deprecated public long getExpireAt();
-    method @Deprecated public long getExpireIn();
-    method @Deprecated public long getFastestInterval();
-    method @Deprecated public boolean getHideFromAppOps();
-    method @Deprecated public long getInterval();
-    method @Deprecated public int getNumUpdates();
-    method @Deprecated @NonNull public String getProvider();
-    method @Deprecated public float getSmallestDisplacement();
-    method @NonNull public android.os.WorkSource getWorkSource();
-    method public boolean isAdasGnssBypass();
-    method public boolean isHiddenFromAppOps();
-    method public boolean isLocationSettingsIgnored();
-    method public boolean isLowPower();
-    method @Deprecated public boolean isLowPowerMode();
-    method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
-    method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
-    method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
-    method @Deprecated public void setHideFromAppOps(boolean);
-    method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
-    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
-    method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
-    method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
-    method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
-    method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
-    method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
-    method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
-    field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
-    field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
-    field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
-    field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
-    field @Deprecated public static final int POWER_LOW = 201; // 0xc9
-    field @Deprecated public static final int POWER_NONE = 200; // 0xc8
-  }
-
-  public static final class LocationRequest.Builder {
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
-    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
-  }
-
-  public final class SatellitePvt implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo();
-    method public int getEphemerisSource();
-    method @FloatRange public double getIonoDelayMeters();
-    method @IntRange(from=0, to=1023) public int getIssueOfDataClock();
-    method @IntRange(from=0, to=1023) public int getIssueOfDataEphemeris();
-    method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef();
-    method @IntRange(from=0) public long getTimeOfClockSeconds();
-    method @IntRange(from=0) public long getTimeOfEphemerisSeconds();
-    method @FloatRange public double getTropoDelayMeters();
-    method @Nullable public android.location.SatellitePvt.VelocityEcef getVelocityEcef();
-    method public boolean hasIono();
-    method public boolean hasIssueOfDataClock();
-    method public boolean hasIssueOfDataEphemeris();
-    method public boolean hasPositionVelocityClockInfo();
-    method public boolean hasTimeOfClockSeconds();
-    method public boolean hasTimeOfEphemerisSeconds();
-    method public boolean hasTropo();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt> CREATOR;
-    field public static final int EPHEMERIS_SOURCE_DEMODULATED = 0; // 0x0
-    field public static final int EPHEMERIS_SOURCE_OTHER = 3; // 0x3
-    field public static final int EPHEMERIS_SOURCE_SERVER_LONG_TERM = 2; // 0x2
-    field public static final int EPHEMERIS_SOURCE_SERVER_NORMAL = 1; // 0x1
-  }
-
-  public static final class SatellitePvt.Builder {
-    ctor public SatellitePvt.Builder();
-    method @NonNull public android.location.SatellitePvt build();
-    method @NonNull public android.location.SatellitePvt.Builder setClockInfo(@NonNull android.location.SatellitePvt.ClockInfo);
-    method @NonNull public android.location.SatellitePvt.Builder setEphemerisSource(int);
-    method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
-    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataClock(@IntRange(from=0, to=1023) int);
-    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataEphemeris(@IntRange(from=0, to=1023) int);
-    method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef);
-    method @NonNull public android.location.SatellitePvt.Builder setTimeOfClockSeconds(@IntRange(from=0) long);
-    method @NonNull public android.location.SatellitePvt.Builder setTimeOfEphemerisSeconds(@IntRange(from=0) long);
-    method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
-    method @NonNull public android.location.SatellitePvt.Builder setVelocityEcef(@NonNull android.location.SatellitePvt.VelocityEcef);
-  }
-
-  public static final class SatellitePvt.ClockInfo implements android.os.Parcelable {
-    ctor public SatellitePvt.ClockInfo(double, double, double);
-    method public int describeContents();
-    method @FloatRange public double getClockDriftMetersPerSecond();
-    method @FloatRange public double getHardwareCodeBiasMeters();
-    method @FloatRange public double getTimeCorrectionMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.ClockInfo> CREATOR;
-  }
-
-  public static final class SatellitePvt.PositionEcef implements android.os.Parcelable {
-    ctor public SatellitePvt.PositionEcef(double, double, double, double);
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreMeters();
-    method @FloatRange public double getXMeters();
-    method @FloatRange public double getYMeters();
-    method @FloatRange public double getZMeters();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.PositionEcef> CREATOR;
-  }
-
-  public static final class SatellitePvt.VelocityEcef implements android.os.Parcelable {
-    ctor public SatellitePvt.VelocityEcef(double, double, double, double);
-    method public int describeContents();
-    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreRateMetersPerSecond();
-    method @FloatRange public double getXMetersPerSecond();
-    method @FloatRange public double getYMetersPerSecond();
-    method @FloatRange public double getZMetersPerSecond();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.VelocityEcef> CREATOR;
-  }
-
-}
-
-package android.location.provider {
-
-  public abstract class LocationProviderBase {
-    ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties);
-    method @Nullable public final android.os.IBinder getBinder();
-    method @NonNull public android.location.provider.ProviderProperties getProperties();
-    method public boolean isAllowed();
-    method public abstract void onFlush(@NonNull android.location.provider.LocationProviderBase.OnFlushCompleteCallback);
-    method public abstract void onSendExtraCommand(@NonNull String, @Nullable android.os.Bundle);
-    method public abstract void onSetRequest(@NonNull android.location.provider.ProviderRequest);
-    method public void reportLocation(@NonNull android.location.Location);
-    method public void reportLocations(@NonNull java.util.List<android.location.Location>);
-    method public void setAllowed(boolean);
-    method public void setProperties(@NonNull android.location.provider.ProviderProperties);
-    field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
-    field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
-    field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
-  }
-
-  public static interface LocationProviderBase.OnFlushCompleteCallback {
-    method public void onFlushComplete();
-  }
-
-  public final class ProviderRequest implements android.os.Parcelable {
-    method public int describeContents();
-    method @IntRange(from=0) public long getIntervalMillis();
-    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
-    method public int getQuality();
-    method @NonNull public android.os.WorkSource getWorkSource();
-    method public boolean isActive();
-    method public boolean isLocationSettingsIgnored();
-    method public boolean isLowPower();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderRequest> CREATOR;
-    field @NonNull public static final android.location.provider.ProviderRequest EMPTY_REQUEST;
-    field public static final long INTERVAL_DISABLED = 9223372036854775807L; // 0x7fffffffffffffffL
-  }
-
-  public static final class ProviderRequest.Builder {
-    ctor public ProviderRequest.Builder();
-    method @NonNull public android.location.provider.ProviderRequest build();
-    method @NonNull public android.location.provider.ProviderRequest.Builder setIntervalMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setLocationSettingsIgnored(boolean);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setLowPower(boolean);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setQuality(int);
-    method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
-  }
-
-  public static interface ProviderRequest.ChangedListener {
-    method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
-  }
-
 }
 
 package android.media {
@@ -7276,8 +6650,11 @@
 
 package android.media.audiopolicy {
 
-  public class AudioMix {
+  public class AudioMix implements android.os.Parcelable {
+    method public int describeContents();
     method public int getMixState();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioMix> CREATOR;
     field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
     field public static final int MIX_STATE_IDLE = 0; // 0x0
     field public static final int MIX_STATE_MIXING = 1; // 0x1
@@ -7286,15 +6663,18 @@
   }
 
   public static class AudioMix.Builder {
-    ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
+    ctor public AudioMix.Builder(@NonNull android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
-    method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+    method public android.media.audiopolicy.AudioMix.Builder setFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
   }
 
-  public class AudioMixingRule {
+  public class AudioMixingRule implements android.os.Parcelable {
+    method public int describeContents();
     method public int getTargetMixRole();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioMixingRule> CREATOR;
     field public static final int MIX_ROLE_INJECTOR = 1; // 0x1
     field public static final int MIX_ROLE_PLAYERS = 0; // 0x0
     field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
@@ -7331,6 +6711,7 @@
     method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
     method public boolean setUserIdDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
     method public String toLogFriendlyString();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int updateMixingRules(@NonNull java.util.List<android.util.Pair<android.media.audiopolicy.AudioMix,android.media.audiopolicy.AudioMixingRule>>);
     field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
     field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
     field public static final int FOCUS_POLICY_DUCKING_IN_POLICY = 1; // 0x1
@@ -13257,6 +12638,48 @@
     method @NonNull public android.service.voice.HotwordRejectedResult.Builder setConfidenceLevel(int);
   }
 
+  public final class HotwordTrainingAudio implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.media.AudioFormat getAudioFormat();
+    method @NonNull public int getAudioType();
+    method @NonNull public byte[] getHotwordAudio();
+    method public int getHotwordOffsetMillis();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordTrainingAudio> CREATOR;
+    field public static final int HOTWORD_OFFSET_UNSET = -1; // 0xffffffff
+  }
+
+  public static final class HotwordTrainingAudio.Builder {
+    ctor public HotwordTrainingAudio.Builder(@NonNull byte[], @NonNull android.media.AudioFormat);
+    method @NonNull public android.service.voice.HotwordTrainingAudio build();
+    method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setAudioFormat(@NonNull android.media.AudioFormat);
+    method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setAudioType(@NonNull int);
+    method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setHotwordAudio(@NonNull byte...);
+    method @NonNull public android.service.voice.HotwordTrainingAudio.Builder setHotwordOffsetMillis(int);
+  }
+
+  public final class HotwordTrainingData implements android.os.Parcelable {
+    method public int describeContents();
+    method public static int getMaxTrainingDataSize();
+    method public int getTimeoutStage();
+    method @NonNull public java.util.List<android.service.voice.HotwordTrainingAudio> getTrainingAudios();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordTrainingData> CREATOR;
+    field public static final int TIMEOUT_STAGE_EARLY = 2; // 0x2
+    field public static final int TIMEOUT_STAGE_LATE = 4; // 0x4
+    field public static final int TIMEOUT_STAGE_MIDDLE = 3; // 0x3
+    field public static final int TIMEOUT_STAGE_UNKNOWN = 0; // 0x0
+    field public static final int TIMEOUT_STAGE_VERY_EARLY = 1; // 0x1
+  }
+
+  public static final class HotwordTrainingData.Builder {
+    ctor public HotwordTrainingData.Builder();
+    method @NonNull public android.service.voice.HotwordTrainingData.Builder addTrainingAudio(@NonNull android.service.voice.HotwordTrainingAudio);
+    method @NonNull public android.service.voice.HotwordTrainingData build();
+    method @NonNull public android.service.voice.HotwordTrainingData.Builder setTimeoutStage(int);
+    method @NonNull public android.service.voice.HotwordTrainingData.Builder setTrainingAudios(@NonNull java.util.List<android.service.voice.HotwordTrainingAudio>);
+  }
+
   public interface SandboxedDetectionInitializer {
     method public static int getMaxCustomInitializationStatus();
     method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer);
@@ -17274,7 +16697,6 @@
     field public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; // 0x2
     field public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; // 0x4
     field public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0
-    field public static final int SATELLITE_ACCESS_BARRED = 16; // 0x10
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6
@@ -17284,13 +16706,6 @@
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3; // 0x3
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2; // 0x2
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1; // 0xffffffff
-    field public static final int SATELLITE_ERROR = 1; // 0x1
-    field public static final int SATELLITE_ERROR_NONE = 0; // 0x0
-    field public static final int SATELLITE_INVALID_ARGUMENTS = 8; // 0x8
-    field public static final int SATELLITE_INVALID_MODEM_STATE = 7; // 0x7
-    field public static final int SATELLITE_INVALID_TELEPHONY_STATE = 6; // 0x6
-    field public static final int SATELLITE_MODEM_BUSY = 22; // 0x16
-    field public static final int SATELLITE_MODEM_ERROR = 4; // 0x4
     field public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3
     field public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2
     field public static final int SATELLITE_MODEM_STATE_IDLE = 0; // 0x0
@@ -17298,21 +16713,29 @@
     field public static final int SATELLITE_MODEM_STATE_OFF = 4; // 0x4
     field public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; // 0x5
     field public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; // 0xffffffff
-    field public static final int SATELLITE_NETWORK_ERROR = 5; // 0x5
-    field public static final int SATELLITE_NETWORK_TIMEOUT = 17; // 0x11
-    field public static final int SATELLITE_NOT_AUTHORIZED = 19; // 0x13
-    field public static final int SATELLITE_NOT_REACHABLE = 18; // 0x12
-    field public static final int SATELLITE_NOT_SUPPORTED = 20; // 0x14
-    field public static final int SATELLITE_NO_RESOURCES = 12; // 0xc
-    field public static final int SATELLITE_RADIO_NOT_AVAILABLE = 10; // 0xa
-    field public static final int SATELLITE_REQUEST_ABORTED = 15; // 0xf
-    field public static final int SATELLITE_REQUEST_FAILED = 9; // 0x9
-    field public static final int SATELLITE_REQUEST_IN_PROGRESS = 21; // 0x15
-    field public static final int SATELLITE_REQUEST_NOT_SUPPORTED = 11; // 0xb
-    field public static final int SATELLITE_SERVER_ERROR = 2; // 0x2
-    field public static final int SATELLITE_SERVICE_ERROR = 3; // 0x3
-    field public static final int SATELLITE_SERVICE_NOT_PROVISIONED = 13; // 0xd
-    field public static final int SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14; // 0xe
+    field public static final int SATELLITE_RESULT_ACCESS_BARRED = 16; // 0x10
+    field public static final int SATELLITE_RESULT_ERROR = 1; // 0x1
+    field public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8; // 0x8
+    field public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7; // 0x7
+    field public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6; // 0x6
+    field public static final int SATELLITE_RESULT_MODEM_BUSY = 22; // 0x16
+    field public static final int SATELLITE_RESULT_MODEM_ERROR = 4; // 0x4
+    field public static final int SATELLITE_RESULT_NETWORK_ERROR = 5; // 0x5
+    field public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17; // 0x11
+    field public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19; // 0x13
+    field public static final int SATELLITE_RESULT_NOT_REACHABLE = 18; // 0x12
+    field public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20; // 0x14
+    field public static final int SATELLITE_RESULT_NO_RESOURCES = 12; // 0xc
+    field public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10; // 0xa
+    field public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15; // 0xf
+    field public static final int SATELLITE_RESULT_REQUEST_FAILED = 9; // 0x9
+    field public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21; // 0x15
+    field public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11; // 0xb
+    field public static final int SATELLITE_RESULT_SERVER_ERROR = 2; // 0x2
+    field public static final int SATELLITE_RESULT_SERVICE_ERROR = 3; // 0x3
+    field public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13; // 0xd
+    field public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14; // 0xe
+    field public static final int SATELLITE_RESULT_SUCCESS = 0; // 0x0
   }
 
   public static class SatelliteManager.SatelliteException extends java.lang.Exception {
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 6c23327..e7c0a91 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -135,16 +135,6 @@
     SAM-compatible parameters (such as parameter 1, "pw", in android.content.pm.ResolveInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.location.Location#dump(android.util.Printer, String):
     SAM-compatible parameters (such as parameter 1, "pw", in android.location.Location.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioFocusRequest.Builder#setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler):
     SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioFocusRequest.Builder.setOnAudioFocusChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
 SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int):
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 1c10356..aa17df3 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -114,20 +114,6 @@
 
 }
 
-package android.location {
-
-  public class LocationManager {
-    method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
-    method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
-    method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
-  }
-
-}
-
 package android.media.tv {
 
   public final class TvInputManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index d43d785..642813f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -28,6 +28,7 @@
     field public static final String MANAGE_APP_OPS_MODES = "android.permission.MANAGE_APP_OPS_MODES";
     field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
     field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
+    field public static final String MANAGE_REMOTE_AUTH = "android.permission.MANAGE_REMOTE_AUTH";
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String MANAGE_TOAST_RATE_LIMITING = "android.permission.MANAGE_TOAST_RATE_LIMITING";
     field public static final String MODIFY_HDR_CONVERSION_MODE = "android.permission.MODIFY_HDR_CONVERSION_MODE";
@@ -54,6 +55,7 @@
     field public static final String TEST_INPUT_METHOD = "android.permission.TEST_INPUT_METHOD";
     field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
+    field public static final String USE_REMOTE_AUTH = "android.permission.USE_REMOTE_AUTH";
     field public static final String WRITE_ALLOWLISTED_DEVICE_CONFIG = "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -497,14 +499,14 @@
     method public int describeContents();
     method public int getActivityType();
     method @Nullable public android.graphics.Rect getAppBounds();
-    method public android.graphics.Rect getBounds();
+    method @NonNull public android.graphics.Rect getBounds();
     method @NonNull public android.graphics.Rect getMaxBounds();
     method public int getRotation();
     method public int getWindowingMode();
     method public static boolean isFloating(int);
     method public void setActivityType(int);
     method public void setAppBounds(@Nullable android.graphics.Rect);
-    method public void setBounds(android.graphics.Rect);
+    method public void setBounds(@Nullable android.graphics.Rect);
     method public void setMaxBounds(@Nullable android.graphics.Rect);
     method public void setRotation(int);
     method public void setTo(android.app.WindowConfiguration);
@@ -1746,109 +1748,6 @@
 
 }
 
-package android.location {
-
-  public final class GnssClock implements android.os.Parcelable {
-    ctor public GnssClock();
-    method public void reset();
-    method public void resetBiasNanos();
-    method public void resetBiasUncertaintyNanos();
-    method public void resetDriftNanosPerSecond();
-    method public void resetDriftUncertaintyNanosPerSecond();
-    method public void resetElapsedRealtimeNanos();
-    method public void resetElapsedRealtimeUncertaintyNanos();
-    method public void resetFullBiasNanos();
-    method public void resetLeapSecond();
-    method public void resetReferenceCarrierFrequencyHzForIsb();
-    method public void resetReferenceCodeTypeForIsb();
-    method public void resetReferenceConstellationTypeForIsb();
-    method public void resetTimeUncertaintyNanos();
-    method public void set(android.location.GnssClock);
-    method public void setBiasNanos(double);
-    method public void setBiasUncertaintyNanos(@FloatRange(from=0.0f) double);
-    method public void setDriftNanosPerSecond(double);
-    method public void setDriftUncertaintyNanosPerSecond(@FloatRange(from=0.0f) double);
-    method public void setElapsedRealtimeNanos(long);
-    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0f) double);
-    method public void setFullBiasNanos(long);
-    method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(int);
-    method public void setReferenceCarrierFrequencyHzForIsb(@FloatRange(from=0.0) double);
-    method public void setReferenceCodeTypeForIsb(@NonNull String);
-    method public void setReferenceConstellationTypeForIsb(int);
-    method public void setTimeNanos(long);
-    method public void setTimeUncertaintyNanos(@FloatRange(from=0.0f) double);
-  }
-
-  public final class GnssMeasurement implements android.os.Parcelable {
-    ctor public GnssMeasurement();
-    method public void reset();
-    method public void resetAutomaticGainControlLevel();
-    method public void resetBasebandCn0DbHz();
-    method @Deprecated public void resetCarrierCycles();
-    method public void resetCarrierFrequencyHz();
-    method @Deprecated public void resetCarrierPhase();
-    method @Deprecated public void resetCarrierPhaseUncertainty();
-    method public void resetCodeType();
-    method public void resetCorrelationVectors();
-    method public void resetFullInterSignalBiasNanos();
-    method public void resetFullInterSignalBiasUncertaintyNanos();
-    method public void resetSatelliteInterSignalBiasNanos();
-    method public void resetSatelliteInterSignalBiasUncertaintyNanos();
-    method public void resetSatellitePvt();
-    method public void resetSnrInDb();
-    method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeMeters(double);
-    method public void setAccumulatedDeltaRangeState(int);
-    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
-    method @Deprecated public void setAutomaticGainControlLevelInDb(double);
-    method public void setBasebandCn0DbHz(double);
-    method @Deprecated public void setCarrierCycles(long);
-    method public void setCarrierFrequencyHz(float);
-    method @Deprecated public void setCarrierPhase(double);
-    method @Deprecated public void setCarrierPhaseUncertainty(double);
-    method public void setCn0DbHz(double);
-    method public void setCodeType(@NonNull String);
-    method public void setConstellationType(int);
-    method public void setCorrelationVectors(@Nullable java.util.Collection<android.location.CorrelationVector>);
-    method public void setFullInterSignalBiasNanos(double);
-    method public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
-    method public void setMultipathIndicator(int);
-    method public void setPseudorangeRateMetersPerSecond(double);
-    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
-    method public void setReceivedSvTimeNanos(long);
-    method public void setReceivedSvTimeUncertaintyNanos(long);
-    method public void setSatelliteInterSignalBiasNanos(double);
-    method public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
-    method public void setSatellitePvt(@Nullable android.location.SatellitePvt);
-    method public void setSnrInDb(double);
-    method public void setState(int);
-    method public void setSvid(int);
-    method public void setTimeOffsetNanos(double);
-    field public static final int ADR_STATE_ALL = 31; // 0x1f
-  }
-
-  public final class GnssNavigationMessage implements android.os.Parcelable {
-    ctor public GnssNavigationMessage();
-    method public void reset();
-    method public void set(android.location.GnssNavigationMessage);
-    method public void setData(byte[]);
-    method public void setMessageId(@IntRange(from=0xffffffff, to=120) int);
-    method public void setStatus(int);
-    method public void setSubmessageId(@IntRange(from=1) int);
-    method public void setSvid(@IntRange(from=1, to=200) int);
-    method public void setType(int);
-  }
-
-  public class LocationManager {
-    method @NonNull public String[] getBackgroundThrottlingWhitelist();
-    method @NonNull public android.os.PackageTagsList getIgnoreSettingsAllowlist();
-    method @Deprecated @NonNull public String[] getIgnoreSettingsWhitelist();
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
-  }
-
-}
-
 package android.media {
 
   public final class AudioAttributes implements android.os.Parcelable {
@@ -2245,6 +2144,10 @@
     method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void unplugBattery(boolean);
   }
 
+  public final class BugreportParams {
+    field public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
+  }
+
   public class Build {
     method public static boolean is64BitAbi(String);
     method public static boolean isDebuggable();
@@ -2706,7 +2609,7 @@
 package android.os.vibrator.persistence {
 
   public class ParsedVibration {
-    method @NonNull public java.util.List<android.os.VibrationEffect> getVibrationEffectListForTesting();
+    method @NonNull public java.util.List<android.os.VibrationEffect> getVibrationEffects();
     method @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator);
   }
 
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 4a97280..1aaedab 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -87,50 +87,6 @@
     Methods must not throw generic exceptions (`java.lang.Exception`)
 
 
-GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
-    Symmetric method for `hasBiasNanos` must be named `setHasBiasNanos`; was `setBiasNanos`
-GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
-    Symmetric method for `hasBiasUncertaintyNanos` must be named `setHasBiasUncertaintyNanos`; was `setBiasUncertaintyNanos`
-GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
-    Symmetric method for `hasDriftNanosPerSecond` must be named `setHasDriftNanosPerSecond`; was `setDriftNanosPerSecond`
-GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
-    Symmetric method for `hasDriftUncertaintyNanosPerSecond` must be named `setHasDriftUncertaintyNanosPerSecond`; was `setDriftUncertaintyNanosPerSecond`
-GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
-    Symmetric method for `hasElapsedRealtimeNanos` must be named `setHasElapsedRealtimeNanos`; was `setElapsedRealtimeNanos`
-GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
-    Symmetric method for `hasElapsedRealtimeUncertaintyNanos` must be named `setHasElapsedRealtimeUncertaintyNanos`; was `setElapsedRealtimeUncertaintyNanos`
-GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
-    Symmetric method for `hasFullBiasNanos` must be named `setHasFullBiasNanos`; was `setFullBiasNanos`
-GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
-    Symmetric method for `hasLeapSecond` must be named `setHasLeapSecond`; was `setLeapSecond`
-GetterSetterNames: android.location.GnssClock#setReferenceCarrierFrequencyHzForIsb(double):
-    Symmetric method for `hasReferenceCarrierFrequencyHzForIsb` must be named `setHasReferenceCarrierFrequencyHzForIsb`; was `setReferenceCarrierFrequencyHzForIsb`
-GetterSetterNames: android.location.GnssClock#setReferenceCodeTypeForIsb(String):
-    Symmetric method for `hasReferenceCodeTypeForIsb` must be named `setHasReferenceCodeTypeForIsb`; was `setReferenceCodeTypeForIsb`
-GetterSetterNames: android.location.GnssClock#setReferenceConstellationTypeForIsb(int):
-    Symmetric method for `hasReferenceConstellationTypeForIsb` must be named `setHasReferenceConstellationTypeForIsb`; was `setReferenceConstellationTypeForIsb`
-GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
-    Symmetric method for `hasTimeUncertaintyNanos` must be named `setHasTimeUncertaintyNanos`; was `setTimeUncertaintyNanos`
-GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
-    Symmetric method for `hasBasebandCn0DbHz` must be named `setHasBasebandCn0DbHz`; was `setBasebandCn0DbHz`
-GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
-    Symmetric method for `hasCarrierFrequencyHz` must be named `setHasCarrierFrequencyHz`; was `setCarrierFrequencyHz`
-GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
-    Symmetric method for `hasCodeType` must be named `setHasCodeType`; was `setCodeType`
-GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
-    Symmetric method for `hasCorrelationVectors` must be named `setHasCorrelationVectors`; was `setCorrelationVectors`
-GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
-    Symmetric method for `hasFullInterSignalBiasNanos` must be named `setHasFullInterSignalBiasNanos`; was `setFullInterSignalBiasNanos`
-GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasUncertaintyNanos(double):
-    Symmetric method for `hasFullInterSignalBiasUncertaintyNanos` must be named `setHasFullInterSignalBiasUncertaintyNanos`; was `setFullInterSignalBiasUncertaintyNanos`
-GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
-    Symmetric method for `hasSatelliteInterSignalBiasNanos` must be named `setHasSatelliteInterSignalBiasNanos`; was `setSatelliteInterSignalBiasNanos`
-GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
-    Symmetric method for `hasSatelliteInterSignalBiasUncertaintyNanos` must be named `setHasSatelliteInterSignalBiasUncertaintyNanos`; was `setSatelliteInterSignalBiasUncertaintyNanos`
-GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
-    Symmetric method for `hasSatellitePvt` must be named `setHasSatellitePvt`; was `setSatellitePvt`
-GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
-    Symmetric method for `hasSnrInDb` must be named `setHasSnrInDb`; was `setSnrInDb`
 GetterSetterNames: android.net.NetworkPolicyManager#getRestrictBackground():
     Symmetric method for `setRestrictBackground` must be named `isRestrictBackground`; was `getRestrictBackground`
 
@@ -343,14 +299,6 @@
     Missing nullability on method `getCameraIdListNoLazy` return
 MissingNullability: android.hardware.display.AmbientDisplayConfiguration#AmbientDisplayConfiguration(android.content.Context) parameter #0:
     Missing nullability on parameter `context` in method `AmbientDisplayConfiguration`
-MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
-    Missing nullability on parameter `clock` in method `set`
-MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
-    Missing nullability on parameter `measurement` in method `set`
-MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
-    Missing nullability on parameter `navigationMessage` in method `set`
-MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
-    Missing nullability on parameter `value` in method `setData`
 MissingNullability: android.media.AudioAttributes#getSdkUsages():
     Missing nullability on method `getSdkUsages` return
 MissingNullability: android.media.AudioManager#getPublicStreamTypes():
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 021f932..32c40df 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -35,6 +35,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityPresentationInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
 import android.content.pm.UserInfo;
 import android.net.Uri;
 import android.os.Bundle;
@@ -1224,4 +1225,13 @@
      */
     @NonNull
     public abstract StatsEvent getCachedAppsHighWatermarkStats(int atomTag, boolean resetAfterPull);
+
+    /**
+     * Internal method for clearing app data, with the extra param that is used to indicate restore.
+     * Used by Backup service during restore operation.
+     *
+     * @hide
+     */
+    public abstract boolean clearApplicationUserData(String packageName, boolean keepState,
+            boolean isRestore, IPackageDataObserver observer, int userId);
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1665cc1..39589fa 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -29,6 +29,8 @@
 import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE;
 import static android.content.ContentResolver.DEPRECATE_DATA_COLUMNS;
 import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
+import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
@@ -206,6 +208,7 @@
 import android.window.WindowProviderService;
 import android.window.WindowTokenClientController;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
@@ -6112,9 +6115,21 @@
         final boolean shouldUpdateResources = hasPublicResConfigChange
                 || shouldUpdateResources(activityToken, currentResConfig, newConfig,
                 amOverrideConfig, movedToDifferentDisplay, hasPublicResConfigChange);
-        final boolean shouldReportChange = shouldReportChange(
-                activity.mCurrentConfig, newConfig, r.mSizeConfigurations,
-                activity.mActivityInfo.getRealConfigChanged(), alwaysReportChange);
+
+        // TODO(b/274944389): remove once a longer-term solution is implemented.
+        boolean skipActivityRelaunchWhenDocking = activity.getResources().getBoolean(
+                R.bool.config_skipActivityRelaunchWhenDocking);
+        int handledConfigChanges = activity.mActivityInfo.getRealConfigChanged();
+        if (skipActivityRelaunchWhenDocking && onlyDeskInUiModeChanged(activity.mCurrentConfig,
+                newConfig)) {
+            // If we're not relaunching this activity when docking, we should send the configuration
+            // changed event. Pretend as if the activity is handling uiMode config changes in its
+            // manifest so that we'll report any dock changes.
+            handledConfigChanges |= ActivityInfo.CONFIG_UI_MODE;
+        }
+
+        final boolean shouldReportChange = shouldReportChange(activity.mCurrentConfig, newConfig,
+                r.mSizeConfigurations, handledConfigChanges, alwaysReportChange);
         // Nothing significant, don't proceed with updating and reporting.
         if (!shouldUpdateResources && !shouldReportChange) {
             return null;
@@ -6161,6 +6176,25 @@
     }
 
     /**
+     * Returns true if the uiMode configuration changed, and desk mode
+     * ({@link android.content.res.Configuration#UI_MODE_TYPE_DESK}) was the only change to uiMode.
+     */
+    private boolean onlyDeskInUiModeChanged(Configuration oldConfig, Configuration newConfig) {
+        boolean deskModeChanged = isInDeskUiMode(oldConfig) != isInDeskUiMode(newConfig);
+
+        // UI mode contains fields other than the UI mode type, so determine if any other fields
+        // changed.
+        boolean uiModeOtherFieldsChanged =
+                (oldConfig.uiMode & ~UI_MODE_TYPE_MASK) != (newConfig.uiMode & ~UI_MODE_TYPE_MASK);
+
+        return deskModeChanged && !uiModeOtherFieldsChanged;
+    }
+
+    private static boolean isInDeskUiMode(Configuration config) {
+        return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_DESK;
+    }
+
+    /**
      * Returns {@code true} if {@link Activity#onConfigurationChanged(Configuration)} should be
      * dispatched.
      *
diff --git a/core/java/android/app/AppOps.md b/core/java/android/app/AppOps.md
index 4589a71..7b11a03 100644
--- a/core/java/android/app/AppOps.md
+++ b/core/java/android/app/AppOps.md
@@ -59,8 +59,8 @@
 : Throw a `SecurityException` on access. This can be suppressed by using a `...noThrow` method to
 check the mode
 
-The initial state of an app-op is defined in `AppOpsManager.sOpDefaultMode`. Confusingly the
-initial state is often not `MODE_DEFAULT`
+The initial state of an app-op is defined in its `AppOpInfo`. Confusingly the initial state is not
+always `MODE_DEFAULT`, if `AppOpInfo.Builder.setDefaultMode()` is called with a different mode.
 
 Per-package modes can be set using `AppOpsManager.setMode` and per-uid modes can be set using
 `AppOpsManager.setUidMode`.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 56fef1a..dab4110 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1486,13 +1486,13 @@
             AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRIGGER_AUDIO;
 
     /**
-     * Allows the assistant app to get the negative trigger data from the PCC sandbox to improve the
+     * Allows the assistant app to get the training data from the PCC sandbox to improve the
      * hotword training model.
      *
      * @hide
      */
-    public static final int OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO =
-            AppProtoEnums.APP_OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO;
+    public static final int OP_RECEIVE_SANDBOX_TRAINING_DATA =
+            AppProtoEnums.APP_OP_RECEIVE_SANDBOX_TRAINING_DATA;
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1640,7 +1640,7 @@
             OPSTR_CAMERA_SANDBOXED,
             OPSTR_RECORD_AUDIO_SANDBOXED,
             OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
-            OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO
+            OPSTR_RECEIVE_SANDBOX_TRAINING_DATA
     })
     public @interface AppOpString {}
 
@@ -2261,13 +2261,13 @@
             "android:receive_sandbox_trigger_audio";
 
     /**
-     * Allows the assistant app to get the negative trigger data from the PCC sandbox to improve
+     * Allows the assistant app to get the training data from the PCC sandbox to improve
      * the hotword training model.
      *
      * @hide
      */
-    public static final String OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO =
-            "android:receive_sandbox_negative_data_audio";
+    public static final String OPSTR_RECEIVE_SANDBOX_TRAINING_DATA =
+            "android:receive_sandbox_training_data";
 
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
@@ -2811,9 +2811,9 @@
                 OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO,
                 "RECEIVE_SANDBOX_TRIGGER_AUDIO")
                 .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
-        new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO,
-                OPSTR_RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO,
-                "RECEIVE_SANDBOX_NEGATIVE_DATA_AUDIO").build()
+        new AppOpInfo.Builder(OP_RECEIVE_SANDBOX_TRAINING_DATA,
+                OPSTR_RECEIVE_SANDBOX_TRAINING_DATA,
+                "RECEIVE_SANDBOX_TRAINING_DATA").build()
     };
 
     // The number of longs needed to form a full bitmask of app ops
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0255860..fcd13b8 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -64,6 +64,7 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
+import android.content.pm.PackageArchiver;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -172,6 +173,7 @@
     private volatile UserManager mUserManager;
     private volatile PermissionManager mPermissionManager;
     private volatile PackageInstaller mInstaller;
+    private volatile PackageArchiver mPackageArchiver;
     private volatile ArtManager mArtManager;
     private volatile DevicePolicyManager mDevicePolicyManager;
     private volatile String mPermissionsControllerPackageName;
@@ -3282,6 +3284,18 @@
     }
 
     @Override
+    public PackageArchiver getPackageArchiver() {
+        if (mPackageArchiver == null) {
+            try {
+                mPackageArchiver = new PackageArchiver(mContext, mPM.getPackageArchiverService());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+        return mPackageArchiver;
+    }
+
+    @Override
     public boolean isPackageAvailable(String packageName) {
         try {
             return mPM.isPackageAvailable(packageName, getUserId());
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5feafbe..a538247 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -3455,20 +3455,20 @@
         mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
         mParams = Objects.requireNonNull(params);
         mAttributionSource = createAttributionSource(attributionTag, nextAttributionSource,
-                params.getRenouncedPermissions());
+                params.getRenouncedPermissions(), params.shouldRegisterAttributionSource());
         mContentResolver = new ApplicationContentResolver(this, mainThread);
     }
 
     private @NonNull AttributionSource createAttributionSource(@Nullable String attributionTag,
             @Nullable AttributionSource nextAttributionSource,
-            @Nullable Set<String> renouncedPermissions) {
+            @Nullable Set<String> renouncedPermissions, boolean shouldRegister) {
         AttributionSource attributionSource = new AttributionSource(Process.myUid(),
                 Process.myPid(), mOpPackageName, attributionTag,
                 (renouncedPermissions != null) ? renouncedPermissions.toArray(new String[0]) : null,
                 getDeviceId(), nextAttributionSource);
         // If we want to access protected data on behalf of another app we need to
         // tell the OS that we opt in to participate in the attribution chain.
-        if (nextAttributionSource != null) {
+        if (nextAttributionSource != null || shouldRegister) {
             attributionSource = getSystemService(PermissionManager.class)
                     .registerAttributionSource(attributionSource);
         }
diff --git a/core/java/android/app/IUriGrantsManager.aidl b/core/java/android/app/IUriGrantsManager.aidl
index 9e7f2fe..b630d03 100644
--- a/core/java/android/app/IUriGrantsManager.aidl
+++ b/core/java/android/app/IUriGrantsManager.aidl
@@ -39,4 +39,7 @@
     void clearGrantedUriPermissions(in String packageName, int userId);
     ParceledListSlice getUriPermissions(in String packageName, boolean incoming,
             boolean persistedOnly);
+
+    int checkGrantUriPermission_ignoreNonSystem(
+            int sourceUid, String targetPkg, in Uri uri, int modeFlags, int userId);
 }
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index bf238c3..019a1a8 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -267,12 +267,13 @@
         }
     };
 
-    // TODO(b/297672475): make this take @Nullable
     /**
      * Sets the bounds to the provided {@link Rect}.
+     * Passing {@code null} sets the bounds {@link Rect} to empty.
+     *
      * @param rect the new bounds value.
      */
-    public void setBounds(Rect rect) {
+    public void setBounds(@Nullable Rect rect) {
         if (rect == null) {
             mBounds.setEmpty();
             return;
@@ -282,8 +283,10 @@
     }
 
     /**
-     * Set {@link #mAppBounds} to the input Rect.
-     * @param rect The rect value to set {@link #mAppBounds} to.
+     * Sets the app bounds to the provided {@link Rect}.
+     * Passing {@code null} sets the bounds to {@code null}.
+     *
+     * @param rect the new app bounds value.
      * @see #getAppBounds()
      */
     public void setAppBounds(@Nullable Rect rect) {
@@ -297,7 +300,9 @@
 
     /**
      * Sets the maximum bounds to the provided {@link Rect}.
-     * @param rect the new bounds value.
+     * Passing {@code null} sets the bounds {@link Rect} to empty.
+     *
+     * @param rect the new max bounds value.
      * @see #getMaxBounds()
      */
     public void setMaxBounds(@Nullable Rect rect) {
@@ -364,8 +369,8 @@
         return mAppBounds;
     }
 
-    // TODO(b/297672475): make this return @NonNull
     /** @see #setBounds(Rect) */
+    @NonNull
     public Rect getBounds() {
         return mBounds;
     }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index d66fca8..ed0f872 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2495,7 +2495,8 @@
                     + ", hints=" + Arrays.toString(node.getAutofillHints())
                     + ", value=" + node.getAutofillValue()
                     + ", sanitized=" + node.isSanitized()
-                    + ", important=" + node.getImportantForAutofill());
+                    + ", important=" + node.getImportantForAutofill()
+                    + ", visibility=" + node.getVisibility());
         }
 
         final int NCHILDREN = node.getChildCount();
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
new file mode 100644
index 0000000..afe87de
--- /dev/null
+++ b/core/java/android/app/usage/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.app.usage"
+
+flag {
+    name: "user_interaction_type_api"
+    namespace: "power_optimization"
+    description: "Feature flag for user interaction event report/query API"
+    bug: "296061232"
+}
+
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 4801d15..c58561d 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -64,12 +64,28 @@
     String getPersistentDeviceId();
 
     /**
+     * Returns the IDs of all virtual displays of this device.
+     */
+    int[] getDisplayIds();
+
+    /**
+     * Returns the device policy for the given policy type.
+     */
+    int getDevicePolicy(int policyType);
+
+    /**
      * 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);
+
+    /**
      * Notifies that an audio session being started.
      */
     @EnforcePermission("CREATE_VIRTUAL_DEVICE")
diff --git a/core/java/android/companion/virtual/IVirtualDeviceListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceListener.aidl
new file mode 100644
index 0000000..c6dd227
--- /dev/null
+++ b/core/java/android/companion/virtual/IVirtualDeviceListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtual;
+
+/**
+ * Interface to listen for changes in the available virtual devices.
+ *
+ * @hide
+ */
+oneway interface IVirtualDeviceListener {
+
+    /**
+     * Called whenever a new virtual device has been added to the system.
+     */
+    void onVirtualDeviceCreated(int deviceId);
+
+    /**
+     * Called whenever a virtual device has been removed from the system.
+     */
+    void onVirtualDeviceClosed(int deviceId);
+}
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index ed8484f..b665036 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -18,6 +18,7 @@
 
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.IVirtualDeviceListener;
 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
 import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceParams;
@@ -56,12 +57,27 @@
      */
     List<VirtualDevice> getVirtualDevices();
 
-   /**
+    /**
+     * Returns the details of the virtual device with the given ID, if any.
+     */
+    VirtualDevice getVirtualDevice(int deviceId);
+
+    /**
+     * Registers a virtual device listener to receive notifications for virtual device events.
+     */
+    void registerVirtualDeviceListener(in IVirtualDeviceListener listener);
+
+    /**
+     * Unregisters a previously registered virtual device listener.
+     */
+    void unregisterVirtualDeviceListener(in IVirtualDeviceListener listener);
+
+    /**
      * Returns the ID of the device which owns the display with the given ID.
      */
     int getDeviceIdForDisplayId(int displayId);
 
-   /**
+    /**
      * Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
      * {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
      * device which is not a virtual device. {@code deviceId} must correspond to a virtual device
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index ceaf7e4..4692f92 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -16,13 +16,17 @@
 
 package android.companion.virtual;
 
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
+
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.companion.virtual.flags.Flags;
 import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
-
-import java.util.Objects;
+import android.os.RemoteException;
 
 /**
  * Details of a particular virtual device.
@@ -31,9 +35,12 @@
  *
  * <p class="note">Not to be confused with {@link VirtualDeviceManager.VirtualDevice}, which is used
  * by the virtual device creator and allows them to manage the device.
+ *
+ * @see VirtualDeviceManager#registerVirtualDeviceListener
  */
 public final class VirtualDevice implements Parcelable {
 
+    private final @NonNull IVirtualDevice mVirtualDevice;
     private final int mId;
     private final @Nullable String mPersistentId;
     private final @Nullable String mName;
@@ -44,17 +51,20 @@
      *
      * @hide
      */
-    public VirtualDevice(int id, @Nullable String persistentId, @Nullable String name) {
+    public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
+            @Nullable String persistentId, @Nullable String name) {
         if (id <= Context.DEVICE_ID_DEFAULT) {
             throw new IllegalArgumentException("VirtualDevice ID must be greater than "
                     + Context.DEVICE_ID_DEFAULT);
         }
+        mVirtualDevice = virtualDevice;
         mId = id;
         mPersistentId = persistentId;
         mName = name;
     }
 
     private VirtualDevice(@NonNull Parcel parcel) {
+        mVirtualDevice = IVirtualDevice.Stub.asInterface(parcel.readStrongBinder());
         mId = parcel.readInt();
         mPersistentId = parcel.readString8();
         mName = parcel.readString8();
@@ -101,6 +111,40 @@
         return mName;
     }
 
+    /**
+     * Returns the IDs of all virtual displays that belong to this device, if any.
+     *
+     * <p>The actual {@link android.view.Display} objects can be obtained by passing the returned
+     * IDs to {@link android.hardware.display.DisplayManager#getDisplay(int)}.</p>
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public @NonNull int[] getDisplayIds() {
+        try {
+            return mVirtualDevice.getDisplayIds();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether this device may have custom sensors.
+     *
+     * <p>Returning {@code true} does not necessarily mean that this device has sensors, it only
+     * means that a {@link android.hardware.SensorManager} instance created from a {@link Context}
+     * associated with this device will return this device's sensors, if any.</p>
+     *
+     * @see Context#getDeviceId()
+     * @see Context#createDeviceContext(int)
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public boolean hasCustomSensorSupport() {
+        try {
+            return mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS) == DEVICE_POLICY_CUSTOM;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -108,31 +152,13 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeStrongBinder(mVirtualDevice.asBinder());
         dest.writeInt(mId);
         dest.writeString8(mPersistentId);
         dest.writeString8(mName);
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (!(o instanceof VirtualDevice)) {
-            return false;
-        }
-        VirtualDevice that = (VirtualDevice) o;
-        return mId == that.mId
-                && Objects.equals(mPersistentId, that.mPersistentId)
-                && Objects.equals(mName, that.mName);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mId, mPersistentId, mName);
-    }
-
-    @Override
     @NonNull
     public String toString() {
         return "VirtualDevice("
diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java
index d13bfd4..2e5c0f7 100644
--- a/core/java/android/companion/virtual/VirtualDeviceInternal.java
+++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java
@@ -238,6 +238,15 @@
         }
     }
 
+    void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
+            @VirtualDeviceParams.DevicePolicy int devicePolicy) {
+        try {
+            mVirtualDevice.setDevicePolicy(policyType, devicePolicy);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @NonNull
     VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
         try {
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 060a5c8..29b0ff3 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -19,6 +19,7 @@
 import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -32,6 +33,7 @@
 import android.companion.AssociationInfo;
 import android.companion.virtual.audio.VirtualAudioDevice;
 import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
+import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.content.ComponentName;
 import android.content.Context;
@@ -53,16 +55,21 @@
 import android.hardware.input.VirtualTouchscreen;
 import android.hardware.input.VirtualTouchscreenConfig;
 import android.media.AudioManager;
+import android.os.Binder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.Surface;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.AnnotationValidations;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
@@ -143,6 +150,9 @@
     private final IVirtualDeviceManager mService;
     private final Context mContext;
 
+    @GuardedBy("mVirtualDeviceListeners")
+    private final List<VirtualDeviceListenerDelegate> mVirtualDeviceListeners = new ArrayList<>();
+
     /** @hide */
     public VirtualDeviceManager(
             @Nullable IVirtualDeviceManager service, @NonNull Context context) {
@@ -173,6 +183,9 @@
             int associationId,
             @NonNull VirtualDeviceParams params) {
         Objects.requireNonNull(params, "params must not be null");
+        if (Flags.moreLogs()) {
+            Log.i(TAG, "Creating VirtualDevice");
+        }
         try {
             return new VirtualDevice(mService, mContext, associationId, params);
         } catch (RemoteException e) {
@@ -200,6 +213,88 @@
     }
 
     /**
+     * Returns the details of the virtual device with the given ID, if any.
+     *
+     * <p>The returned object is a read-only representation of the virtual device that expose its
+     * properties.</p>
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    @Nullable
+    public android.companion.virtual.VirtualDevice getVirtualDevice(int deviceId) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
+            return null;
+        }
+        if (deviceId == Context.DEVICE_ID_INVALID || deviceId == Context.DEVICE_ID_DEFAULT) {
+            return null;  // Don't even bother making a Binder call.
+        }
+        try {
+            return mService.getVirtualDevice(deviceId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Registers a virtual device listener to receive notifications when virtual devices are created
+     * or closed.
+     *
+     * @param executor The executor where the listener is executed on.
+     * @param listener The listener to add.
+     * @see #unregisterVirtualDeviceListener
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public void registerVirtualDeviceListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull VirtualDeviceListener listener) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to register listener; no virtual device manager service.");
+            return;
+        }
+        final VirtualDeviceListenerDelegate delegate =
+                new VirtualDeviceListenerDelegate(Objects.requireNonNull(executor),
+                        Objects.requireNonNull(listener));
+        synchronized (mVirtualDeviceListeners) {
+            try {
+                mService.registerVirtualDeviceListener(delegate);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mVirtualDeviceListeners.add(delegate);
+        }
+    }
+
+    /**
+     * Unregisters a virtual device listener previously registered with
+     * {@link #registerVirtualDeviceListener}.
+     *
+     * @param listener The listener to unregister.
+     * @see #registerVirtualDeviceListener
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public void unregisterVirtualDeviceListener(@NonNull VirtualDeviceListener listener) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to unregister listener; no virtual device manager service.");
+            return;
+        }
+        Objects.requireNonNull(listener);
+        synchronized (mVirtualDeviceListeners) {
+            final Iterator<VirtualDeviceListenerDelegate> it = mVirtualDeviceListeners.iterator();
+            while (it.hasNext()) {
+                final VirtualDeviceListenerDelegate delegate = it.next();
+                if (delegate.mListener == listener) {
+                    try {
+                        mService.unregisterVirtualDeviceListener(delegate);
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
+                    }
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    /**
      * Returns the device policy for the given virtual device and policy type.
      *
      * <p>In case the virtual device identifier is not valid, or there's no explicitly specified
@@ -509,6 +604,28 @@
         }
 
         /**
+         * Specifies a policy for this virtual device.
+         *
+         * <p>Policies define the system behavior that may be specific for this virtual device. The
+         * given policy must be able to be changed dynamically during the lifetime of the device.
+         *
+         * @param policyType the type of policy, i.e. which behavior to specify a policy for.
+         * @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
+         *
+         * @see VirtualDeviceParams#POLICY_TYPE_RECENTS
+         */
+        @FlaggedApi(Flags.FLAG_DYNAMIC_POLICY)
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
+                @VirtualDeviceParams.DevicePolicy int devicePolicy) {
+            AnnotationValidations.validate(
+                    VirtualDeviceParams.DynamicPolicyType.class, null, policyType);
+            AnnotationValidations.validate(
+                    VirtualDeviceParams.DevicePolicy.class, null, devicePolicy);
+            mVirtualDeviceInternal.setDevicePolicy(policyType, devicePolicy);
+        }
+
+        /**
          * Creates a virtual dpad.
          *
          * @param config the configurations of the virtual dpad.
@@ -719,7 +836,7 @@
          *
          * @param executor The executor where the listener is executed on.
          * @param soundEffectListener The listener to add.
-         * @see #removeActivityListener(ActivityListener)
+         * @see #removeSoundEffectListener(SoundEffectListener)
          */
         public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor,
                 @NonNull SoundEffectListener soundEffectListener) {
@@ -848,4 +965,59 @@
          */
         void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType);
     }
+
+    /**
+     * Listener for changes in the available virtual devices.
+     */
+    @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+    public interface VirtualDeviceListener {
+        /**
+         * Called whenever a new virtual device has been added to the system.
+         * Use {@link VirtualDeviceManager#getVirtualDevice(int)} to get more information about
+         * the device.
+         *
+         * @param deviceId The id of the virtual device that was added.
+         */
+        default void onVirtualDeviceCreated(int deviceId) {}
+
+        /**
+         * Called whenever a virtual device has been removed from the system.
+         *
+         * @param deviceId The id of the virtual device that was removed.
+         */
+        default void onVirtualDeviceClosed(int deviceId) {}
+    }
+
+    /**
+     * A wrapper for {@link VirtualDeviceListener} that executes callbacks on the given executor.
+     */
+    private static class VirtualDeviceListenerDelegate extends IVirtualDeviceListener.Stub {
+        private final VirtualDeviceListener mListener;
+        private final Executor mExecutor;
+
+        private VirtualDeviceListenerDelegate(Executor executor, VirtualDeviceListener listener) {
+            mExecutor = executor;
+            mListener = listener;
+        }
+
+        @Override
+        public void onVirtualDeviceCreated(int deviceId) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mListener.onVirtualDeviceCreated(deviceId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void onVirtualDeviceClosed(int deviceId) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mListener.onVirtualDeviceClosed(deviceId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
 }
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index b6d8375..51df257 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -150,6 +150,17 @@
     public @interface PolicyType {}
 
     /**
+     * Policy types that can be dynamically changed during the virtual device's lifetime.
+     *
+     * @see VirtualDeviceManager.VirtualDevice#setDevicePolicy
+     * @hide
+     */
+    @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS})
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+    public @interface DynamicPolicyType {}
+
+    /**
      * Tells the sensor framework how to handle sensor requests from contexts associated with this
      * virtual device, namely the sensors returned by
      * {@link android.hardware.SensorManager#getSensorList}:
@@ -191,14 +202,12 @@
 
     private final int mLockState;
     @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
-    @NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
-    @NonNull private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
     @NavigationPolicy
     private final int mDefaultNavigationPolicy;
-    @NonNull private final ArraySet<ComponentName> mAllowedActivities;
-    @NonNull private final ArraySet<ComponentName> mBlockedActivities;
+    @NonNull private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
     @ActivityPolicy
     private final int mDefaultActivityPolicy;
+    @NonNull private final ArraySet<ComponentName> mActivityPolicyExceptions;
     @Nullable private final String mName;
     // Mapping of @PolicyType to @DevicePolicy
     @NonNull private final SparseIntArray mDevicePolicies;
@@ -210,12 +219,10 @@
     private VirtualDeviceParams(
             @LockState int lockState,
             @NonNull Set<UserHandle> usersWithMatchingAccounts,
-            @NonNull Set<ComponentName> allowedCrossTaskNavigations,
-            @NonNull Set<ComponentName> blockedCrossTaskNavigations,
             @NavigationPolicy int defaultNavigationPolicy,
-            @NonNull Set<ComponentName> allowedActivities,
-            @NonNull Set<ComponentName> blockedActivities,
+            @NonNull Set<ComponentName> crossTaskNavigationExceptions,
             @ActivityPolicy int defaultActivityPolicy,
+            @NonNull Set<ComponentName> activityPolicyExceptions,
             @Nullable String name,
             @NonNull SparseIntArray devicePolicies,
             @NonNull List<VirtualSensorConfig> virtualSensorConfigs,
@@ -225,14 +232,12 @@
         mLockState = lockState;
         mUsersWithMatchingAccounts =
                 new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts));
-        mAllowedCrossTaskNavigations =
-                new ArraySet<>(Objects.requireNonNull(allowedCrossTaskNavigations));
-        mBlockedCrossTaskNavigations =
-                new ArraySet<>(Objects.requireNonNull(blockedCrossTaskNavigations));
         mDefaultNavigationPolicy = defaultNavigationPolicy;
-        mAllowedActivities = new ArraySet<>(Objects.requireNonNull(allowedActivities));
-        mBlockedActivities = new ArraySet<>(Objects.requireNonNull(blockedActivities));
+        mCrossTaskNavigationExceptions =
+                new ArraySet<>(Objects.requireNonNull(crossTaskNavigationExceptions));
         mDefaultActivityPolicy = defaultActivityPolicy;
+        mActivityPolicyExceptions =
+                new ArraySet<>(Objects.requireNonNull(activityPolicyExceptions));
         mName = name;
         mDevicePolicies = Objects.requireNonNull(devicePolicies);
         mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
@@ -245,12 +250,10 @@
     private VirtualDeviceParams(Parcel parcel) {
         mLockState = parcel.readInt();
         mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
-        mAllowedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
-        mBlockedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mDefaultNavigationPolicy = parcel.readInt();
-        mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
-        mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
+        mCrossTaskNavigationExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mDefaultActivityPolicy = parcel.readInt();
+        mActivityPolicyExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
         mName = parcel.readString8();
         mDevicePolicies = parcel.readSparseIntArray();
         mVirtualSensorConfigs = new ArrayList<>();
@@ -290,7 +293,9 @@
      */
     @NonNull
     public Set<ComponentName> getAllowedCrossTaskNavigations() {
-        return Collections.unmodifiableSet(mAllowedCrossTaskNavigations);
+        return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_ALLOWED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
     }
 
     /**
@@ -303,7 +308,9 @@
      */
     @NonNull
     public Set<ComponentName> getBlockedCrossTaskNavigations() {
-        return Collections.unmodifiableSet(mBlockedCrossTaskNavigations);
+        return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_BLOCKED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
     }
 
     /**
@@ -327,7 +334,9 @@
      */
     @NonNull
     public Set<ComponentName> getAllowedActivities() {
-        return Collections.unmodifiableSet(mAllowedActivities);
+        return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mActivityPolicyExceptions);
     }
 
     /**
@@ -338,7 +347,9 @@
      */
     @NonNull
     public Set<ComponentName> getBlockedActivities() {
-        return Collections.unmodifiableSet(mBlockedActivities);
+        return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED
+                ? Collections.emptySet()
+                : Collections.unmodifiableSet(mActivityPolicyExceptions);
     }
 
     /**
@@ -375,6 +386,14 @@
     }
 
     /**
+     * Returns all device policies.
+     * @hide
+     */
+    public @NonNull SparseIntArray getDevicePolicies() {
+        return mDevicePolicies;
+    }
+
+    /**
      * Returns the configurations for all sensors that should be created for this device.
      *
      * @see Builder#addVirtualSensorConfig
@@ -420,12 +439,10 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeInt(mLockState);
         dest.writeArraySet(mUsersWithMatchingAccounts);
-        dest.writeArraySet(mAllowedCrossTaskNavigations);
-        dest.writeArraySet(mBlockedCrossTaskNavigations);
         dest.writeInt(mDefaultNavigationPolicy);
-        dest.writeArraySet(mAllowedActivities);
-        dest.writeArraySet(mBlockedActivities);
+        dest.writeArraySet(mCrossTaskNavigationExceptions);
         dest.writeInt(mDefaultActivityPolicy);
+        dest.writeArraySet(mActivityPolicyExceptions);
         dest.writeString8(mName);
         dest.writeSparseIntArray(mDevicePolicies);
         dest.writeTypedList(mVirtualSensorConfigs);
@@ -458,11 +475,10 @@
         }
         return mLockState == that.mLockState
                 && mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
-                && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
-                && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations)
+                && Objects.equals(
+                        mCrossTaskNavigationExceptions, that.mCrossTaskNavigationExceptions)
                 && mDefaultNavigationPolicy == that.mDefaultNavigationPolicy
-                && Objects.equals(mAllowedActivities, that.mAllowedActivities)
-                && Objects.equals(mBlockedActivities, that.mBlockedActivities)
+                && Objects.equals(mActivityPolicyExceptions, that.mActivityPolicyExceptions)
                 && mDefaultActivityPolicy == that.mDefaultActivityPolicy
                 && Objects.equals(mName, that.mName)
                 && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
@@ -472,10 +488,9 @@
     @Override
     public int hashCode() {
         int hashCode = Objects.hash(
-                mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
-                mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
-                mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies,
-                mAudioPlaybackSessionId, mAudioRecordingSessionId);
+                mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExceptions,
+                mDefaultNavigationPolicy, mActivityPolicyExceptions, mDefaultActivityPolicy, mName,
+                mDevicePolicies, mAudioPlaybackSessionId, mAudioRecordingSessionId);
         for (int i = 0; i < mDevicePolicies.size(); i++) {
             hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
             hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -489,12 +504,10 @@
         return "VirtualDeviceParams("
                 + " mLockState=" + mLockState
                 + " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
-                + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations
-                + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations
                 + " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy
-                + " mAllowedActivities=" + mAllowedActivities
-                + " mBlockedActivities=" + mBlockedActivities
+                + " mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions
                 + " mDefaultActivityPolicy=" + mDefaultActivityPolicy
+                + " mActivityPolicyExceptions=" + mActivityPolicyExceptions
                 + " mName=" + mName
                 + " mDevicePolicies=" + mDevicePolicies
                 + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
@@ -510,13 +523,11 @@
         pw.println(prefix + "mName=" + mName);
         pw.println(prefix + "mLockState=" + mLockState);
         pw.println(prefix + "mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts);
-        pw.println(prefix + "mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations);
-        pw.println(prefix + "mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations);
-        pw.println(prefix + "mAllowedActivities=" + mAllowedActivities);
-        pw.println(prefix + "mBlockedActivities=" + mBlockedActivities);
-        pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
         pw.println(prefix + "mDefaultNavigationPolicy=" + mDefaultNavigationPolicy);
+        pw.println(prefix + "mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions);
         pw.println(prefix + "mDefaultActivityPolicy=" + mDefaultActivityPolicy);
+        pw.println(prefix + "mActivityPolicyExceptions=" + mActivityPolicyExceptions);
+        pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
         pw.println(prefix + "mVirtualSensorConfigs=" + mVirtualSensorConfigs);
         pw.println(prefix + "mAudioPlaybackSessionId=" + mAudioPlaybackSessionId);
         pw.println(prefix + "mAudioRecordingSessionId=" + mAudioRecordingSessionId);
@@ -541,13 +552,11 @@
 
         private @LockState int mLockState = LOCK_STATE_DEFAULT;
         @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();
-        @NonNull private Set<ComponentName> mAllowedCrossTaskNavigations = Collections.emptySet();
-        @NonNull private Set<ComponentName> mBlockedCrossTaskNavigations = Collections.emptySet();
+        @NonNull private Set<ComponentName> mCrossTaskNavigationExceptions = Collections.emptySet();
         @NavigationPolicy
         private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
         private boolean mDefaultNavigationPolicyConfigured = false;
-        @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
-        @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
+        @NonNull private Set<ComponentName> mActivityPolicyExceptions = Collections.emptySet();
         @ActivityPolicy
         private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
         private boolean mDefaultActivityPolicyConfigured = false;
@@ -686,12 +695,12 @@
             if (mDefaultNavigationPolicyConfigured
                     && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) {
                 throw new IllegalArgumentException(
-                     "Allowed cross task navigation and blocked task navigation cannot "
+                     "Allowed cross task navigations and blocked cross task navigations cannot "
                      + " both be set.");
             }
             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
             mDefaultNavigationPolicyConfigured = true;
-            mAllowedCrossTaskNavigations = Objects.requireNonNull(allowedCrossTaskNavigations);
+            mCrossTaskNavigationExceptions = Objects.requireNonNull(allowedCrossTaskNavigations);
             return this;
         }
 
@@ -722,7 +731,7 @@
             }
             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
             mDefaultNavigationPolicyConfigured = true;
-            mBlockedCrossTaskNavigations = Objects.requireNonNull(blockedCrossTaskNavigations);
+            mCrossTaskNavigationExceptions = Objects.requireNonNull(blockedCrossTaskNavigations);
             return this;
         }
 
@@ -748,7 +757,7 @@
             }
             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED;
             mDefaultActivityPolicyConfigured = true;
-            mAllowedActivities = Objects.requireNonNull(allowedActivities);
+            mActivityPolicyExceptions = Objects.requireNonNull(allowedActivities);
             return this;
         }
 
@@ -774,7 +783,7 @@
             }
             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
             mDefaultActivityPolicyConfigured = true;
-            mBlockedActivities = Objects.requireNonNull(blockedActivities);
+            mActivityPolicyExceptions = Objects.requireNonNull(blockedActivities);
             return this;
         }
 
@@ -969,12 +978,10 @@
             return new VirtualDeviceParams(
                     mLockState,
                     mUsersWithMatchingAccounts,
-                    mAllowedCrossTaskNavigations,
-                    mBlockedCrossTaskNavigations,
                     mDefaultNavigationPolicy,
-                    mAllowedActivities,
-                    mBlockedActivities,
+                    mCrossTaskNavigationExceptions,
                     mDefaultActivityPolicy,
+                    mActivityPolicyExceptions,
                     mName,
                     mDevicePolicies,
                     mVirtualSensorConfigs,
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
new file mode 100644
index 0000000..9ab3be6
--- /dev/null
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -0,0 +1,22 @@
+package: "android.companion.virtual.flags"
+
+flag {
+  name: "more_logs"
+  namespace: "virtual_devices"
+  description: "More logs to test flags with"
+  bug: "291725823"
+}
+
+flag {
+  name: "dynamic_policy"
+  namespace: "virtual_devices"
+  description: "Enable dynamic policy API"
+  bug: "298401780"
+}
+
+flag {
+  name: "vdm_public_apis"
+  namespace: "virtual_devices"
+  description: "Enable public VDM API for device capabilities"
+  bug: "297253526"
+}
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 8f35ca2..15678a7 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -226,6 +226,11 @@
     }
 
     /** @hide */
+    public AttributionSource withDefaultToken() {
+        return withToken(sDefaultToken);
+    }
+
+    /** @hide */
     public AttributionSource withPid(int pid) {
         return new AttributionSource(getUid(), pid, getPackageName(), getAttributionTag(),
                 getToken(), mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
@@ -552,16 +557,28 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         AttributionSource that = (AttributionSource) o;
-        return mAttributionSourceState.uid == that.mAttributionSourceState.uid
+        return equalsExceptToken(that) && Objects.equals(
+                mAttributionSourceState.token, that.mAttributionSourceState.token);
+    }
+
+    /**
+     * We store trusted attribution sources without their token (the token is the key to the map)
+     * to avoid having a strong reference to the token. This means, when checking the equality of a
+     * supplied AttributionSource in PermissionManagerService.isTrustedAttributionSource, we want to
+     * compare everything except the token.
+     *
+     * @hide
+     */
+    public boolean equalsExceptToken(@Nullable AttributionSource o) {
+        if (o == null) return false;
+        return mAttributionSourceState.uid == o.mAttributionSourceState.uid
                 && Objects.equals(mAttributionSourceState.packageName,
-                        that.mAttributionSourceState.packageName)
+                o.mAttributionSourceState.packageName)
                 && Objects.equals(mAttributionSourceState.attributionTag,
-                        that.mAttributionSourceState.attributionTag)
-                && Objects.equals(mAttributionSourceState.token,
-                        that.mAttributionSourceState.token)
+                o.mAttributionSourceState.attributionTag)
                 && Arrays.equals(mAttributionSourceState.renouncedPermissions,
-                        that.mAttributionSourceState.renouncedPermissions)
-                && Objects.equals(getNext(), that.getNext());
+                o.mAttributionSourceState.renouncedPermissions)
+                && Objects.equals(getNext(), o.getNext());
     }
 
     @Override
diff --git a/core/java/android/content/ContextParams.java b/core/java/android/content/ContextParams.java
index 5cc3a24..988a9c0 100644
--- a/core/java/android/content/ContextParams.java
+++ b/core/java/android/content/ContextParams.java
@@ -50,17 +50,20 @@
     private final @Nullable String mAttributionTag;
     private final @Nullable AttributionSource mNext;
     private final @NonNull Set<String> mRenouncedPermissions;
+    private final boolean mShouldRegisterAttributionSource;
 
     /** {@hide} */
     public static final ContextParams EMPTY = new ContextParams.Builder().build();
 
     private ContextParams(@Nullable String attributionTag,
             @Nullable AttributionSource next,
-            @Nullable Set<String> renouncedPermissions) {
+            @Nullable Set<String> renouncedPermissions,
+            boolean shouldRegister) {
         mAttributionTag = attributionTag;
         mNext = next;
         mRenouncedPermissions = (renouncedPermissions != null)
                 ? renouncedPermissions : Collections.emptySet();
+        mShouldRegisterAttributionSource = shouldRegister;
     }
 
     /**
@@ -95,12 +98,22 @@
     }
 
     /**
+     * @return Whether the attribution source associated with the Context being created should be
+     * registered.
+     */
+    @NonNull
+    public boolean shouldRegisterAttributionSource() {
+        return mShouldRegisterAttributionSource;
+    }
+
+    /**
      * Builder for creating a {@link ContextParams}.
      */
     public static final class Builder {
         private @Nullable String mAttributionTag;
         private @NonNull Set<String> mRenouncedPermissions = Collections.emptySet();
         private @Nullable AttributionSource mNext;
+        private boolean mShouldRegisterAttributionSource;
 
         /**
          * Create a new builder.
@@ -159,6 +172,19 @@
         }
 
         /**
+         * Sets whether the attribution source associated with the context created from these params
+         * should be registered.
+         *
+         * @param shouldRegister Whether the attribution source associated with the Context being
+         *                       created should be registered.
+         */
+        @NonNull
+        public Builder setShouldRegisterAttributionSource(boolean shouldRegister) {
+            mShouldRegisterAttributionSource = shouldRegister;
+            return this;
+        }
+
+        /**
          * Sets permissions which have been voluntarily "renounced" by the
          * calling app.
          * <p>
@@ -205,7 +231,7 @@
         @NonNull
         public ContextParams build() {
             return new ContextParams(mAttributionTag, mNext,
-                    mRenouncedPermissions);
+                    mRenouncedPermissions, mShouldRegisterAttributionSource);
         }
     }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index afeb3d29..fe7d1e6 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5270,6 +5270,16 @@
     public static final String ACTION_SHOW_FOREGROUND_SERVICE_MANAGER =
             "android.intent.action.SHOW_FOREGROUND_SERVICE_MANAGER";
 
+    /**
+     * Broadcast Action: Sent to the responsible installer of an archived package when unarchival
+     * is requested.
+     *
+     * @see android.content.pm.PackageArchiver
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UNARCHIVE_PACKAGE = "android.intent.action.UNARCHIVE_PACKAGE";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
@@ -6705,6 +6715,15 @@
     public static final String EXTRA_VISIBILITY_ALLOW_LIST =
             "android.intent.extra.VISIBILITY_ALLOW_LIST";
 
+    /**
+     * A boolean extra used with {@link #ACTION_PACKAGE_DATA_CLEARED} which indicates if the intent
+     * is broadcast as part of a restore operation.
+     *
+     * @hide
+     */
+    public static final String EXTRA_IS_RESTORE =
+            "android.intent.extra.IS_RESTORE";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/content/pm/ArchivedPackageParcel.aidl b/core/java/android/content/pm/ArchivedPackageParcel.aidl
new file mode 100644
index 0000000..6aeee89
--- /dev/null
+++ b/core/java/android/content/pm/ArchivedPackageParcel.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.content.pm.SigningDetails;
+
+/**
+ * Contains fields required for archived package installation,
+ * i.e. installation without an APK.
+ * @hide
+ */
+parcelable ArchivedPackageParcel {
+    String packageName;
+    SigningDetails signingDetails;
+    int versionCode;
+    int versionCodeMajor;
+    int targetSdkVersion;
+    boolean backupAllowed;
+    boolean defaultToDeviceProtectedStorage;
+    boolean requestLegacyExternalStorage;
+    boolean userDataFragile;
+    boolean clearUserDataOnFailedRestoreAllowed;
+}
diff --git a/core/java/android/content/pm/IPackageArchiverService.aidl b/core/java/android/content/pm/IPackageArchiverService.aidl
new file mode 100644
index 0000000..dc6491d
--- /dev/null
+++ b/core/java/android/content/pm/IPackageArchiverService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm;
+
+import android.content.IntentSender;
+import android.os.UserHandle;
+
+/** {@hide} */
+interface IPackageArchiverService {
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES,android.Manifest.permission.REQUEST_DELETE_PACKAGES})")
+    void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})")
+    void requestUnarchive(String packageName, String callerPackageName, in UserHandle userHandle);
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index ea0f5ff..916c249 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -22,9 +22,11 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.ChangedPackages;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.IPackageArchiverService;
 import android.content.pm.IDexModuleRegisterCallback;
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.IOnChecksumsReadyListener;
@@ -650,6 +652,8 @@
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
     IPackageInstaller getPackageInstaller();
 
+    IPackageArchiverService getPackageArchiverService();
+
     @EnforcePermission("DELETE_PACKAGES")
     boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
     @UnsupportedAppUsage
@@ -830,4 +834,6 @@
     void registerPackageMonitorCallback(IRemoteCallback callback, int userId);
 
     void unregisterPackageMonitorCallback(IRemoteCallback callback);
+
+    ArchivedPackageParcel getArchivedPackage(in String apkPath);
 }
diff --git a/core/java/android/content/pm/PackageArchiver.java b/core/java/android/content/pm/PackageArchiver.java
new file mode 100644
index 0000000..b065231
--- /dev/null
+++ b/core/java/android/content/pm/PackageArchiver.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.IntentSender;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.ParcelableException;
+import android.os.RemoteException;
+
+/**
+ * {@code ArchiveManager} is used to archive apps. During the archival process, the apps APKs and
+ * cache are removed from the device while the user data is kept. Through the
+ * {@code requestUnarchive()} call, apps can be restored again through their responsible app store.
+ *
+ * <p> Archived apps are returned as displayable apps through the {@link LauncherApps} APIs and
+ * will be displayed to users with UI treatment to highlight that said apps are archived. If
+ * a user taps on an archived app, the app will be unarchived and the restoration process is
+ * communicated.
+ *
+ * @hide
+ */
+// TODO(b/278560219) Improve public documentation.
+@SystemApi
+public class PackageArchiver {
+
+    /**
+     * Extra field for the package name of a package that is requested to be unarchived. Sent as
+     * part of the {@link android.content.Intent#ACTION_UNARCHIVE_PACKAGE} intent.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_UNARCHIVE_PACKAGE_NAME =
+            "android.content.pm.extra.UNARCHIVE_PACKAGE_NAME";
+
+    /**
+     * If true, the requestor of the unarchival has specified that the app should be unarchived
+     * for {@link android.os.UserHandle#ALL}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_UNARCHIVE_ALL_USERS =
+            "android.content.pm.extra.UNARCHIVE_ALL_USERS";
+
+    private final Context mContext;
+    private final IPackageArchiverService mService;
+
+    /**
+     * @hide
+     */
+    public PackageArchiver(Context context, IPackageArchiverService service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Requests to archive a package which is currently installed.
+     *
+     * @param statusReceiver Callback used to notify when the operation is completed.
+     * @throws NameNotFoundException If {@code packageName} isn't found or not available to the
+     *                               caller or isn't archived.
+     * @hide
+     */
+    @RequiresPermission(anyOf = {
+            Manifest.permission.DELETE_PACKAGES,
+            Manifest.permission.REQUEST_DELETE_PACKAGES})
+    @SystemApi
+    public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver)
+            throws NameNotFoundException {
+        try {
+            mService.requestArchive(packageName, mContext.getPackageName(), statusReceiver,
+                    mContext.getUser());
+        } catch (ParcelableException e) {
+            e.maybeRethrow(NameNotFoundException.class);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Requests to unarchive a currently archived package.
+     *
+     * <p> Sends a request to unarchive an app to the responsible installer. The installer is
+     * determined by {@link InstallSourceInfo#getUpdateOwnerPackageName()}, or
+     * {@link InstallSourceInfo#getInstallingPackageName()} if the former value is null.
+     *
+     * <p> The installation will happen asynchronously and can be observed through
+     * {@link android.content.Intent#ACTION_PACKAGE_ADDED}.
+     *
+     * @throws NameNotFoundException If {@code packageName} isn't found or not visible to the
+     *                               caller or if the package has no installer on the device
+     *                               anymore to unarchive it.
+     * @hide
+     */
+    @RequiresPermission(anyOf = {
+            Manifest.permission.INSTALL_PACKAGES,
+            Manifest.permission.REQUEST_INSTALL_PACKAGES})
+    @SystemApi
+    public void requestUnarchive(@NonNull String packageName)
+            throws NameNotFoundException {
+        try {
+            mService.requestUnarchive(packageName, mContext.getPackageName(), mContext.getUser());
+        } catch (ParcelableException e) {
+            e.maybeRethrow(NameNotFoundException.class);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 63c11b7..cdb8b46 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -488,6 +489,17 @@
      */
     public boolean isActiveApex;
 
+    /**
+     * Whether the package is currently in an archived state.
+     *
+     * <p>Packages can be archived through {@link PackageArchiver} and do not have any APKs stored
+     * on the device, but do keep the data directory.
+     * @hide
+     */
+    // TODO(b/278553670) Unhide and update @links before launch.
+    @SystemApi
+    public boolean isArchived;
+
     public PackageInfo() {
     }
 
@@ -575,6 +587,7 @@
         }
         dest.writeBoolean(isApex);
         dest.writeBoolean(isActiveApex);
+        dest.writeBoolean(isArchived);
         dest.restoreAllowSquashing(prevAllowSquashing);
     }
 
@@ -640,5 +653,6 @@
         }
         isApex = source.readBoolean();
         isActiveApex = source.readBoolean();
+        isArchived = source.readBoolean();
     }
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 885e67e1..9a53a2a6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -787,6 +787,7 @@
             MATCH_DEBUG_TRIAGED_MISSING,
             MATCH_INSTANT,
             MATCH_APEX,
+            MATCH_ARCHIVED_PACKAGES,
             GET_DISABLED_COMPONENTS,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
@@ -811,6 +812,7 @@
             GET_UNINSTALLED_PACKAGES,
             MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
             MATCH_APEX,
+            MATCH_ARCHIVED_PACKAGES,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationInfoFlagsBits {}
@@ -1235,6 +1237,21 @@
     public static final long GET_ATTRIBUTIONS_LONG = 0x80000000L;
 
     /**
+     * Flag parameter to also retrieve some information about archived packages.
+     * Packages can be archived through {@link PackageArchiver} and do not have any APKs stored on
+     * the device, but do keep the data directory.
+     * <p> Note: Archived apps are a subset of apps returned by {@link #MATCH_UNINSTALLED_PACKAGES}.
+     * <p> Note: this flag may cause less information about currently installed
+     * applications to be returned.
+     * <p> Note: use of this flag requires the android.permission.QUERY_ALL_PACKAGES
+     * permission to see uninstalled packages.
+     * @hide
+     */
+    // TODO(b/278553670) Unhide and update @links before launch.
+    @SystemApi
+    public static final long MATCH_ARCHIVED_PACKAGES = 1L << 32;
+
+    /**
      * @hide
      */
     public static final long FILTER_OUT_QUARANTINED_COMPONENTS = 0x100000000L;
@@ -1682,6 +1699,13 @@
     public static final int INSTALL_FROM_MANAGED_USER_OR_PROFILE = 1 << 26;
 
     /**
+     * Flag parameter for {@link PackageInstaller.SessionParams} to indicate that this
+     * session is for archived package installation.
+     * @hide
+     */
+    public static final int INSTALL_ARCHIVED = 1 << 27;
+
+    /**
      * Flag parameter for {@link #installPackage} to force a non-staged update of an APEX. This is
      * a development-only feature and should not be used on end user devices.
      *
@@ -9934,6 +9958,16 @@
     public abstract @NonNull PackageInstaller getPackageInstaller();
 
     /**
+     * {@link PackageArchiver} can be used to archive and restore archived packages.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @NonNull PackageArchiver getPackageArchiver() {
+        throw new UnsupportedOperationException(
+                "getPackageArchiver not implemented in subclass");
+    }
+    /**
      * Adds a {@code CrossProfileIntentFilter}. After calling this method all
      * intents sent from the user with id sourceUserId can also be be resolved
      * by activities in the user with id targetUserId if they match the
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/core/java/android/content/pm/SigningDetails.aidl
similarity index 71%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to core/java/android/content/pm/SigningDetails.aidl
index 24064b1..95f3ca7 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/core/java/android/content/pm/SigningDetails.aidl
@@ -13,14 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.content.pm;
 
-package com.android.systemui.scene.ui.composable
-
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
-
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
-}
+parcelable SigningDetails;
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index ea21d51..ab669cc 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -48,9 +48,6 @@
             "name":"CarrierAppIntegrationTestCases"
         },
         {
-            "name":"ApkVerityTest"
-        },
-        {
             "name":"CtsSilentUpdateHostTestCases"
         },
         {
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 269bec2..8e7592a 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.SigningDetails;
@@ -138,6 +139,34 @@
      */
     private final boolean mIsSdkLibrary;
 
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    private final boolean mBackupAllowed;
+
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    private final boolean mDefaultToDeviceProtectedStorage;
+
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    private final boolean mRequestLegacyExternalStorage;
+
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    private final boolean mUserDataFragile;
+
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    private final boolean mClearUserDataOnFailedRestoreAllowed;
+
     public ApkLite(String path, String packageName, String splitName, boolean isFeatureSplit,
             String configForSplit, String usesSplitName, boolean isSplitRequired, int versionCode,
             int versionCodeMajor, int revisionCode, int installLocation,
@@ -148,7 +177,10 @@
             String requiredSystemPropertyName, String requiredSystemPropertyValue,
             int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
             Set<String> requiredSplitTypes, Set<String> splitTypes,
-            boolean hasDeviceAdminReceiver, boolean isSdkLibrary) {
+            boolean hasDeviceAdminReceiver, boolean isSdkLibrary, boolean clearUserDataAllowed,
+            boolean backupAllowed, boolean defaultToDeviceProtectedStorage,
+            boolean requestLegacyExternalStorage, boolean userDataFragile,
+            boolean clearUserDataOnFailedRestoreAllowed) {
         mPath = path;
         mPackageName = packageName;
         mSplitName = splitName;
@@ -182,6 +214,52 @@
         mRollbackDataPolicy = rollbackDataPolicy;
         mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
         mIsSdkLibrary = isSdkLibrary;
+        mBackupAllowed = backupAllowed;
+        mDefaultToDeviceProtectedStorage = defaultToDeviceProtectedStorage;
+        mRequestLegacyExternalStorage = requestLegacyExternalStorage;
+        mUserDataFragile = userDataFragile;
+        mClearUserDataOnFailedRestoreAllowed = clearUserDataOnFailedRestoreAllowed;
+    }
+
+    public ApkLite(String path, ArchivedPackageParcel archivedPackage) {
+        mPath = path;
+        mPackageName = archivedPackage.packageName;
+        mSplitName = null; // base.apk
+        mSplitTypes = null;
+        mFeatureSplit = false;
+        mConfigForSplit = null;
+        mUsesSplitName = null;
+        mRequiredSplitTypes = null;
+        mSplitRequired = hasAnyRequiredSplitTypes();
+        mVersionCode = archivedPackage.versionCode;
+        mVersionCodeMajor = archivedPackage.versionCodeMajor;
+        mRevisionCode = 0;
+        mInstallLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+        mVerifiers = new VerifierInfo[]{};
+        mSigningDetails = archivedPackage.signingDetails;
+        mCoreApp = false;
+        mDebuggable = false;
+        mProfileableByShell = false;
+        mMultiArch = false;
+        mUse32bitAbi = false;
+        mUseEmbeddedDex = false;
+        mExtractNativeLibs = false;
+        mIsolatedSplits = false;
+        mTargetPackageName = null;
+        mOverlayIsStatic = false;
+        mOverlayPriority = 0;
+        mRequiredSystemPropertyName = null;
+        mRequiredSystemPropertyValue = null;
+        mMinSdkVersion = ApkLiteParseUtils.DEFAULT_MIN_SDK_VERSION;
+        mTargetSdkVersion = archivedPackage.targetSdkVersion;
+        mRollbackDataPolicy = 0;
+        mHasDeviceAdminReceiver = false;
+        mIsSdkLibrary = false;
+        mBackupAllowed = archivedPackage.backupAllowed;
+        mDefaultToDeviceProtectedStorage = archivedPackage.defaultToDeviceProtectedStorage;
+        mRequestLegacyExternalStorage = archivedPackage.requestLegacyExternalStorage;
+        mUserDataFragile = archivedPackage.userDataFragile;
+        mClearUserDataOnFailedRestoreAllowed = archivedPackage.clearUserDataOnFailedRestoreAllowed;
     }
 
     /**
@@ -474,6 +552,9 @@
         return mRollbackDataPolicy;
     }
 
+    /**
+     * Indicates if this app contains a {@link android.app.admin.DeviceAdminReceiver}.
+     */
     @DataClass.Generated.Member
     public boolean isHasDeviceAdminReceiver() {
         return mHasDeviceAdminReceiver;
@@ -487,11 +568,54 @@
         return mIsSdkLibrary;
     }
 
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    @DataClass.Generated.Member
+    public boolean isBackupAllowed() {
+        return mBackupAllowed;
+    }
+
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    @DataClass.Generated.Member
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return mDefaultToDeviceProtectedStorage;
+    }
+
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    @DataClass.Generated.Member
+    public boolean isRequestLegacyExternalStorage() {
+        return mRequestLegacyExternalStorage;
+    }
+
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    @DataClass.Generated.Member
+    public boolean isUserDataFragile() {
+        return mUserDataFragile;
+    }
+
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    @DataClass.Generated.Member
+    public boolean isClearUserDataOnFailedRestoreAllowed() {
+        return mClearUserDataOnFailedRestoreAllowed;
+    }
+
     @DataClass.Generated(
-            time = 1643063342990L,
+            time = 1693513509013L,
             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\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 mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\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 4f6bcb6..066ff689 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -40,6 +40,7 @@
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
 
@@ -73,7 +74,7 @@
     // Constants copied from services.jar side since they're not accessible
     private static final String ANDROID_RES_NAMESPACE =
             "http://schemas.android.com/apk/res/android";
-    private static final int DEFAULT_MIN_SDK_VERSION = 1;
+    public static final int DEFAULT_MIN_SDK_VERSION = 1;
     private static final int DEFAULT_TARGET_SDK_VERSION = 0;
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
     private static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
@@ -446,6 +447,13 @@
         int overlayPriority = 0;
         int rollbackDataPolicy = 0;
 
+        boolean clearUserDataAllowed = true;
+        boolean backupAllowed = true;
+        boolean defaultToDeviceProtectedStorage = false;
+        String requestLegacyExternalStorage = null;
+        boolean userDataFragile = false;
+        boolean clearUserDataOnFailedRestoreAllowed = true;
+
         String requiredSystemPropertyName = null;
         String requiredSystemPropertyValue = null;
 
@@ -484,6 +492,23 @@
                         "extractNativeLibs", true);
                 useEmbeddedDex = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
                         "useEmbeddedDex", false);
+
+                clearUserDataAllowed = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+                        "allowClearUserDataOnFailedRestore", true);
+                backupAllowed = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+                        "allowBackup", true);
+                defaultToDeviceProtectedStorage = parser.getAttributeBooleanValue(
+                        ANDROID_RES_NAMESPACE,
+                        "defaultToDeviceProtectedStorage", false);
+                userDataFragile = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+                        "hasFragileUserData", false);
+                clearUserDataOnFailedRestoreAllowed = parser.getAttributeBooleanValue(
+                        ANDROID_RES_NAMESPACE,
+                        "allowClearUserDataOnFailedRestore", true);
+
+                requestLegacyExternalStorage = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
+                        "requestLegacyExternalStorage");
+
                 rollbackDataPolicy = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
                         "rollbackDataPolicy", 0);
                 String permission = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
@@ -604,6 +629,9 @@
             return input.skip(message);
         }
 
+        boolean isRequestLegacyExternalStorage = XmlUtils.convertValueToBoolean(
+                requestLegacyExternalStorage, targetSdkVersion < Build.VERSION_CODES.Q);
+
         return input.success(
                 new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                         configForSplit, usesSplitName, isSplitRequired, versionCode,
@@ -613,7 +641,9 @@
                         overlayIsStatic, overlayPriority, requiredSystemPropertyName,
                         requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
                         rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
-                        hasDeviceAdminReceiver, isSdkLibrary));
+                        hasDeviceAdminReceiver, isSdkLibrary, clearUserDataAllowed, backupAllowed,
+                        defaultToDeviceProtectedStorage, isRequestLegacyExternalStorage,
+                        userDataFragile, clearUserDataOnFailedRestoreAllowed));
     }
 
     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 e2789c9..ccef9de 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackageInfo;
+import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 
 import com.android.internal.util.ArrayUtils;
@@ -78,6 +79,8 @@
     private final int mInstallLocation;
     /** Information about a package verifiers as used during package verification */
     private final @NonNull VerifierInfo[] mVerifiers;
+    /** Signing-related data of an application package */
+    private final @NonNull SigningDetails mSigningDetails;
 
     /** Indicate whether any split APKs that are features. Ordered by splitName */
     private final @Nullable boolean[] mIsFeatureSplits;
@@ -109,6 +112,29 @@
      * Indicates if this package is a sdk.
      */
     private final boolean mIsSdkLibrary;
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    private final boolean mBackupAllowed;
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    private final boolean mDefaultToDeviceProtectedStorage;
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    private final boolean mRequestLegacyExternalStorage;
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    private final boolean mUserDataFragile;
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    private final boolean mClearUserDataOnFailedRestoreAllowed;
 
     public PackageLite(String path, String baseApkPath, ApkLite baseApk,
             String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
@@ -123,6 +149,7 @@
         mVersionCodeMajor = baseApk.getVersionCodeMajor();
         mInstallLocation = baseApk.getInstallLocation();
         mVerifiers = baseApk.getVerifiers();
+        mSigningDetails = baseApk.getSigningDetails();
         mBaseRevisionCode = baseApk.getRevisionCode();
         mCoreApp = baseApk.isCoreApp();
         mDebuggable = baseApk.isDebuggable();
@@ -144,6 +171,11 @@
         mSplitApkPaths = splitApkPaths;
         mSplitRevisionCodes = splitRevisionCodes;
         mTargetSdk = targetSdk;
+        mBackupAllowed = baseApk.isBackupAllowed();
+        mDefaultToDeviceProtectedStorage = baseApk.isDefaultToDeviceProtectedStorage();
+        mRequestLegacyExternalStorage = baseApk.isRequestLegacyExternalStorage();
+        mUserDataFragile = baseApk.isUserDataFragile();
+        mClearUserDataOnFailedRestoreAllowed = baseApk.isClearUserDataOnFailedRestoreAllowed();
     }
 
     /**
@@ -325,6 +357,14 @@
     }
 
     /**
+     * Signing-related data of an application package
+     */
+    @DataClass.Generated.Member
+    public @NonNull SigningDetails getSigningDetails() {
+        return mSigningDetails;
+    }
+
+    /**
      * Indicate whether any split APKs that are features. Ordered by splitName
      */
     @DataClass.Generated.Member
@@ -414,12 +454,54 @@
         return mIsSdkLibrary;
     }
 
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    @DataClass.Generated.Member
+    public boolean isBackupAllowed() {
+        return mBackupAllowed;
+    }
+
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    @DataClass.Generated.Member
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return mDefaultToDeviceProtectedStorage;
+    }
+
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    @DataClass.Generated.Member
+    public boolean isRequestLegacyExternalStorage() {
+        return mRequestLegacyExternalStorage;
+    }
+
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    @DataClass.Generated.Member
+    public boolean isUserDataFragile() {
+        return mUserDataFragile;
+    }
+
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    @DataClass.Generated.Member
+    public boolean isClearUserDataOnFailedRestoreAllowed() {
+        return mClearUserDataOnFailedRestoreAllowed;
+    }
+
     @DataClass.Generated(
-            time = 1643132127068L,
+            time = 1693513525097L,
             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.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\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  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\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/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 76b29e6..5cc3b92 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,7 +27,6 @@
 import android.annotation.RawRes;
 import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
-import android.app.ResourcesManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
@@ -430,49 +429,35 @@
                 if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
                     if (locales.size() > 1) {
                         String[] availableLocales;
-                        if (ResourcesManager.getInstance().getLocaleList().isEmpty()) {
-                            // The LocaleList has changed. We must query the AssetManager's
-                            // available Locales and figure out the best matching Locale in the new
-                            // LocaleList.
-                            availableLocales = mAssets.getNonSystemLocales();
+                        // The LocaleList has changed. We must query the AssetManager's
+                        // available Locales and figure out the best matching Locale in the new
+                        // LocaleList.
+                        availableLocales = mAssets.getNonSystemLocales();
+                        if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
+                            // No app defined locales, so grab the system locales.
+                            availableLocales = mAssets.getLocales();
                             if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
-                                // No app defined locales, so grab the system locales.
-                                availableLocales = mAssets.getLocales();
-                                if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
-                                    availableLocales = null;
-                                }
+                                availableLocales = null;
                             }
+                        }
 
-                            if (availableLocales != null) {
-                                final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
-                                        availableLocales);
-                                if (bestLocale != null) {
-                                    selectedLocales = new String[]{
-                                            adjustLanguageTag(bestLocale.toLanguageTag())};
-                                    if (!bestLocale.equals(locales.get(0))) {
-                                        mConfiguration.setLocales(
-                                                new LocaleList(bestLocale, locales));
-                                    }
+                        if (availableLocales != null) {
+                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
+                                    availableLocales);
+                            if (bestLocale != null) {
+                                selectedLocales = new String[]{
+                                        adjustLanguageTag(bestLocale.toLanguageTag())};
+                                if (!bestLocale.equals(locales.get(0))) {
+                                    mConfiguration.setLocales(
+                                            new LocaleList(bestLocale, locales));
                                 }
                             }
-                        } else {
-                            selectedLocales = locales.getIntersection(
-                                    ResourcesManager.getInstance().getLocaleList());
-                            defaultLocale = ResourcesManager.getInstance()
-                                    .getLocaleList().get(0).toLanguageTag();
                         }
                     }
                 }
                 if (selectedLocales == null) {
-                    if (ResourcesManager.getInstance().getLocaleList().isEmpty()) {
-                        selectedLocales = new String[]{
-                                adjustLanguageTag(locales.get(0).toLanguageTag())};
-                    } else {
-                        selectedLocales = new String[locales.size()];
-                        for (int i = 0; i < locales.size(); i++) {
-                            selectedLocales[i] = adjustLanguageTag(locales.get(i).toLanguageTag());
-                        }
-                    }
+                    selectedLocales = new String[]{
+                            adjustLanguageTag(locales.get(0).toLanguageTag())};
                 }
 
                 if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
diff --git a/core/java/android/hardware/SensorAdditionalInfo.java b/core/java/android/hardware/SensorAdditionalInfo.java
index 59def9f..d1e101d 100644
--- a/core/java/android/hardware/SensorAdditionalInfo.java
+++ b/core/java/android/hardware/SensorAdditionalInfo.java
@@ -257,7 +257,7 @@
     public static SensorAdditionalInfo createLocalGeomagneticField(
             float strength, float declination, float inclination) {
         if (strength < 10 || strength > 100 // much beyond extreme values on earth
-                || declination < 0 || declination > Math.PI
+                || declination < -Math.PI / 2 || declination > Math.PI / 2
                 || inclination < -Math.PI / 2 || inclination > Math.PI / 2) {
             throw new IllegalArgumentException("Geomagnetic field info out of range");
         }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 0f6f601..dfd3802 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -129,6 +129,7 @@
             mDynamicSensorCallbacks = new HashMap<>();
     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
     private BroadcastReceiver mRuntimeSensorBroadcastReceiver;
+    private VirtualDeviceManager.VirtualDeviceListener mVirtualDeviceListener;
 
     // Looper associated with the context in which this instance was created.
     private final Looper mMainLooper;
@@ -518,7 +519,11 @@
     }
 
     private List<Sensor> createRuntimeSensorListLocked(int deviceId) {
-        setupRuntimeSensorBroadcastReceiver();
+        if (android.companion.virtual.flags.Flags.vdmPublicApis()) {
+            setupVirtualDeviceListener();
+        } else {
+            setupRuntimeSensorBroadcastReceiver();
+        }
         List<Sensor> list = new ArrayList<>();
         nativeGetRuntimeSensors(mNativeInstance, deviceId, list);
         mFullRuntimeSensorListByDevice.put(deviceId, list);
@@ -558,6 +563,34 @@
         }
     }
 
+    private void setupVirtualDeviceListener() {
+        if (mVirtualDeviceListener != null) {
+            return;
+        }
+        if (mVdm == null) {
+            mVdm = mContext.getSystemService(VirtualDeviceManager.class);
+            if (mVdm == null) {
+                return;
+            }
+        }
+        mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {
+            @Override
+            public void onVirtualDeviceClosed(int deviceId) {
+                synchronized (mFullRuntimeSensorListByDevice) {
+                    List<Sensor> removedSensors =
+                            mFullRuntimeSensorListByDevice.removeReturnOld(deviceId);
+                    if (removedSensors != null) {
+                        for (Sensor s : removedSensors) {
+                            cleanupSensorConnection(s);
+                        }
+                    }
+                    mRuntimeSensorListByDeviceByType.remove(deviceId);
+                }
+            }
+        };
+        mVdm.registerVirtualDeviceListener(mContext.getMainExecutor(), mVirtualDeviceListener);
+    }
+
     private void setupDynamicSensorBroadcastReceiver() {
         if (mDynamicSensorBroadcastReceiver == null) {
             mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
@@ -581,12 +614,6 @@
         }
     }
 
-    private void teardownDynamicSensorBroadcastReceiver() {
-        mDynamicSensorCallbacks.clear();
-        mContext.unregisterReceiver(mDynamicSensorBroadcastReceiver);
-        mDynamicSensorBroadcastReceiver = null;
-    }
-
     /** @hide */
     protected void registerDynamicSensorCallbackImpl(
             DynamicSensorCallback callback, Handler handler) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index d352be1..943f0c4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -31,6 +32,7 @@
 import android.util.Rational;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.camera.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 082a336..f4d783a 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -625,12 +625,13 @@
      * <style scoped>
      *  #rb { border-right-width: thick; }
      * </style>
+     *
+     * <h5>LEGACY-level guaranteed configurations</h5>
+     *
      * <p>Legacy devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}) support at
      * least the following stream combinations:
      *
-     * <h5>LEGACY-level guaranteed configurations</h5>
-     *
      * <table>
      * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th>  <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
@@ -645,13 +646,13 @@
      * </table><br>
      * </p>
      *
+     * <h5>LIMITED-level additional guaranteed configurations</h5>
+     *
      * <p>Limited-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
      * support at least the following stream combinations in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices:
      *
-     * <h5>LIMITED-level additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
@@ -664,13 +665,13 @@
      * </table><br>
      * </p>
      *
+     * <h5>FULL-level additional guaranteed configurations</h5>
+     *
      * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
      * support at least the following stream combinations in addition to those for
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
      *
-     * <h5>FULL-level additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -683,14 +684,14 @@
      * </table><br>
      * </p>
      *
+     * <h5>RAW-capability additional guaranteed configurations</h5>
+     *
      * <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support
      * at least the following stream combinations on both
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
      *
-     * <h5>RAW-capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -705,6 +706,8 @@
      * </table><br>
      * </p>
      *
+     * <h5>BURST-capability additional guaranteed configurations</h5>
+     *
      * <p>BURST-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}) devices
      * support at least the below stream combinations in addition to those for
@@ -713,8 +716,6 @@
      * list for FULL-level devices, so this table is only relevant for LIMITED-level devices that
      * support the BURST_CAPTURE capability.
      *
-     * <h5>BURST-capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -724,6 +725,8 @@
      * </table><br>
      * </p>
      *
+     * <h5>LEVEL-3 additional guaranteed configurations</h5>
+     *
      * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3})
      * support at least the following stream combinations in addition to the combinations for
@@ -731,8 +734,6 @@
      * RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}):
      *
-     * <h5>LEVEL-3 additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -741,14 +742,16 @@
      * </table><br>
      * </p>
      *
-     *<p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as described by
-     * {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
+     * <h5>Concurrent stream guaranteed configurations</h5>
+     *
+     * <p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as
+     * described by {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
      * following guaranteed streams (when streaming concurrently with other devices)</p>
+     *
      * <p> Note: The sizes mentioned for these concurrent streams are the maximum sizes guaranteed
      * to be supported. Sizes smaller than these, obtained by {@link StreamConfigurationMap#getOutputSizes} for a particular format, are supported as well. </p>
      *
-     * <h5>Concurrent stream guaranteed configurations</h5>
-     *
+     * <p>
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
@@ -784,6 +787,8 @@
      * level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not
      * supported.</p>
      *
+     * <h5>LEGACY-level additional guaranteed combinations with multi-resolution outputs</h5>
+     *
      * <p>Devices capable of multi-resolution output for a particular format (
      * {@link android.hardware.camera2.params.MultiResolutionStreamConfigurationMap#getOutputInfo}
      * returns a non-empty list) support using {@link MultiResolutionImageReader} for MAXIMUM
@@ -794,8 +799,6 @@
      * stream combinations ({@code MULTI_RES} in the Max size column refers to a {@link
      * MultiResolutionImageReader} created based on the variable max resolutions supported):
      *
-     * <h5>LEGACY-level additional guaranteed combinations with MultiResolutionoutputs</h5>
-     *
      * <table>
      * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th>  <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr>
@@ -804,8 +807,12 @@
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Still capture plus in-app processing.</td> </tr>
      * </table><br>
+     * </p>
+     *
+     * <h5>LIMITED-level additional guaranteed configurations with multi-resolution outputs</h5>
+     *
+     * <p>
      * <table>
-     * <tr><th colspan="7">LIMITED-level additional guaranteed configurations with MultiResolutionoutputs</th></tr>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
      * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MULTI_RES}</td> <td>Two-input in-app processing with still capture.</td> </tr>
@@ -813,11 +820,11 @@
      * The same logic applies to other hardware levels and capabilities.
      * </p>
      *
-     * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
-     * which clients can take advantage of : </p>
-     *
      * <h5>Additional guaranteed combinations for ULTRA_HIGH_RESOLUTION sensors</h5>
      *
+     * <p> Devices with the ULTRA_HIGH_RESOLUTION_SENSOR capability have some additional guarantees
+     * which clients can take advantage of:
+     *
      * <table>
      * <tr> <th colspan="3" id="rb">Target 1</th> <th colspan="3" id="rb">Target 2</th>  <th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th> <th>Type</th><th id="rb"> SC Map</th><th id="rb">Max size</th></tr>
@@ -825,6 +832,7 @@
      * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PRIV / YUV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code RECORD}</td> <td>Ultra high res still capture with preview + app based RECORD size analysis</td> </tr>
      * <tr> <td>{@code YUV / JPEG / RAW}</td><td id="rb">{@code MAX_RES}</td><td id="rb">{@code MAX}</td><td id="rb">{@code PRIV}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code JPEG / YUV / RAW}</td><td id="rb">{@code DEFAULT}</td><td id="rb">{@code MAX}</td> <td>Ultra high res still image capture with preview + default sensor pixel mode analysis stream</td> </tr>
      * </table><br>
+     * </p>
      *
      * <p> Here, SC Map, refers to the {@link StreamConfigurationMap}, the target stream sizes must
      * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link
@@ -834,17 +842,17 @@
      * Note: The same capture request must not mix targets from
      * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. </p>
      *
-     * <p> 10-bit output capable
-     * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
-     * devices support at least the following stream combinations: </p>
-     *
      * <h5>10-bit output additional guaranteed configurations</h5>
      *
+     * <p>10-bit output capable
+     * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT}
+     * devices support at least the following stream combinations:
+     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
-     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
-     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> }</td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
+     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr>
+     * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> </td> <td colspan="4" id="rb"></td> <td>In-application video/image processing.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution in-app processing with preview.</td> </tr>
      * <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM }</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution two-input in-app processing.</td> </tr>
@@ -852,6 +860,8 @@
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td>{@code YUV}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with in-app snapshot.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV }</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with video snapshot.</td> </tr>
      * </table><br>
+     * </p>
+     *
      * <p>Here PRIV can be either 8 or 10-bit {@link android.graphics.ImageFormat#PRIVATE} pixel
      * format. YUV can be either {@link android.graphics.ImageFormat#YUV_420_888} or
      * {@link android.graphics.ImageFormat#YCBCR_P010}.
@@ -887,13 +897,13 @@
      * {@link CameraDevice#isSessionConfigurationSupported} to ensure that this particular
      * configuration is supported.</p>
      *
+     * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
+     *
      * <p>Devices with the STREAM_USE_CASE capability ({@link
      * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link
      * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional
      * stream combinations:
      *
-     * <h5>STREAM_USE_CASE capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
@@ -913,12 +923,12 @@
      * </table><br>
      * </p>
      *
+     * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
+     *
      * <p>Devices that include the {@link CameraMetadata#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW}
      * stream use-case in {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES},
      * support the additional stream combinations below:
      *
-     * <h5>STREAM_USE_CASE_CROPPED_RAW capability additional guaranteed configurations</h5>
-     *
      * <table>
      * <tr><th colspan="3" id="rb">Target 1</th><th colspan="3" id="rb">Target 2</th><th colspan="3" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th><th>Type</th><th id="rb">Max size</th><th>Usecase</th> </tr>
@@ -926,16 +936,18 @@
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td colspan="3" id="rb"></td> <td>Preview with cropped RAW still capture</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Preview with YUV / JPEG and cropped RAW still capture</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code VIDEO_RECORD / PREVIEW}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code CROPPED_RAW}</td> <td>Video recording with preview and cropped RAW still capture</td> </tr>
-     *
-     *
-     *<p> For devices where {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES}
-     * includes {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
-     * the following stream combinations are guaranteed,
-     * for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
-     * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION} <p>
+     * </table><br>
+     * </p>
      *
      * <h5>Preview stabilization guaranteed stream configurations</h5>
      *
+     * <p>For devices where
+     * {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES} includes
+     * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION},
+     * the following stream combinations are guaranteed,
+     * for CaptureRequests where {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE} is set to
+     * {@link CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION}
+     *
      * <table>
      * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr>
      * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
@@ -943,6 +955,8 @@
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p}</td> <td>{@code JPEG / YUV}</td><td id="rb">{@code MAXIMUM }</td><td>Standard still imaging with stabilized preview.</td> </tr>
      * <tr> <td>{@code PRIV / YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV / YUV}</td><td id="rb">{@code s1440p }</td><td>High-resolution recording with stabilized preview and recording stream.</td> </tr>
      * </table><br>
+     * </p>
+     *
      * <p>
      * For the maximum size column, PREVIEW refers to the best size match to the device's screen
      * resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 5940819..dd32384 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -34,6 +35,8 @@
 import android.util.SparseArray;
 import android.view.Surface;
 
+import com.android.internal.camera.flags.Flags;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -1468,6 +1471,13 @@
      * <p>Only constrains auto-exposure (AE) algorithm, not
      * manual control of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime} and
      * {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}.</p>
+     * <p>To start a CaptureSession with a target FPS range different from the
+     * capture request template's default value, the application
+     * is strongly recommended to call
+     * {@link SessionConfiguration#setSessionParameters }
+     * with the target fps range before creating the capture session. The aeTargetFpsRange is
+     * typically a session parameter. Specifying it at session creation time helps avoid
+     * session reconfiguration delays in cases like 60fps or high speed recording.</p>
      * <p><b>Units</b>: Frames per second (FPS)</p>
      * <p><b>Range of valid values:</b><br>
      * Any of the entries in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}</p>
@@ -2140,6 +2150,12 @@
      * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return
      * OFF if the recording output is not stabilized, or if there are no output
      * Surface types that can be stabilized.</p>
+     * <p>The application is strongly recommended to call
+     * {@link SessionConfiguration#setSessionParameters }
+     * with the desired video stabilization mode before creating the capture session.
+     * Video stabilization mode is a session parameter on many devices. Specifying
+     * it at session creation time helps avoid reconfiguration delay caused by difference
+     * between the default value and the first CaptureRequest.</p>
      * <p>If a camera device supports both this mode and OIS
      * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
      * produce undesirable interaction, so it is recommended not to enable
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 905f98d..9a80015 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -28,6 +29,8 @@
 import android.util.Log;
 import android.util.Rational;
 
+import com.android.internal.camera.flags.Flags;
+
 import java.util.List;
 
 /**
@@ -887,6 +890,13 @@
      * <p>Only constrains auto-exposure (AE) algorithm, not
      * manual control of {@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime} and
      * {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration}.</p>
+     * <p>To start a CaptureSession with a target FPS range different from the
+     * capture request template's default value, the application
+     * is strongly recommended to call
+     * {@link SessionConfiguration#setSessionParameters }
+     * with the target fps range before creating the capture session. The aeTargetFpsRange is
+     * typically a session parameter. Specifying it at session creation time helps avoid
+     * session reconfiguration delays in cases like 60fps or high speed recording.</p>
      * <p><b>Units</b>: Frames per second (FPS)</p>
      * <p><b>Range of valid values:</b><br>
      * Any of the entries in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}</p>
@@ -2365,6 +2375,12 @@
      * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return
      * OFF if the recording output is not stabilized, or if there are no output
      * Surface types that can be stabilized.</p>
+     * <p>The application is strongly recommended to call
+     * {@link SessionConfiguration#setSessionParameters }
+     * with the desired video stabilization mode before creating the capture session.
+     * Video stabilization mode is a session parameter on many devices. Specifying
+     * it at session creation time helps avoid reconfiguration delay caused by difference
+     * between the default value and the first CaptureRequest.</p>
      * <p>If a camera device supports both this mode and OIS
      * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
      * produce undesirable interaction, so it is recommended not to enable
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 181ab2c..994037b 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1149,11 +1149,7 @@
                             "remove holder for requestId %d, "
                             + "because lastFrame is %d.",
                             requestId, lastFrameNumber));
-                }
-            }
 
-            if (holder != null) {
-                if (DEBUG) {
                     Log.v(TAG, "immediately trigger onCaptureSequenceAborted because"
                             + " request did not reach HAL");
                 }
@@ -2180,11 +2176,9 @@
 
                 final CaptureCallbackHolder holder =
                         CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
-                final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
 
                 boolean isPartialResult =
                         (resultExtras.getPartialResultCount() < mTotalPartialCount);
-                int requestType = request.getRequestType();
 
                 // Check if we have a callback for this
                 if (holder == null) {
@@ -2194,12 +2188,11 @@
                                         + frameNumber);
                     }
 
-                    updateTracker(requestId, frameNumber, requestType, /*result*/null,
-                            isPartialResult);
-
                     return;
                 }
 
+                final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
+                int requestType = request.getRequestType();
                 if (isClosed()) {
                     if (DEBUG) {
                         Log.d(TAG,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8f653b3..f1ae9be 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -650,8 +650,6 @@
 
     private InlineSuggestionSessionController mInlineSuggestionSessionController;
 
-    private boolean mHideNavBarForKeyboard;
-    private boolean mIsAutomotive;
     private @NonNull OptionalInt mHandwritingRequestId = OptionalInt.empty();
     private InputEventReceiver mHandwritingEventReceiver;
     private Handler mHandler;
@@ -892,10 +890,13 @@
             mSystemCallingHideSoftInput = true;
             mCurHideInputToken = hideInputToken;
             mCurStatsToken = statsToken;
-            hideSoftInput(flags, resultReceiver);
-            mCurStatsToken = null;
-            mCurHideInputToken = null;
-            mSystemCallingHideSoftInput = false;
+            try {
+                hideSoftInput(flags, resultReceiver);
+            } finally {
+                mCurStatsToken = null;
+                mCurHideInputToken = null;
+                mSystemCallingHideSoftInput = false;
+            }
         }
 
         /**
@@ -1622,7 +1623,7 @@
         // shown the first time (cold start).
         mSettingsObserver.shouldShowImeWithHardKeyboard();
 
-        mHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
+        final boolean hideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_hideNavBarForKeyboard);
 
         initConfigurationTracker();
@@ -1668,7 +1669,7 @@
             // screen real estate. When this happens, the IME window should animate from the
             // bottom of the screen to reduce the jank that happens from the lack of synchronization
             // between the bottom system window and the IME window.
-            if (mHideNavBarForKeyboard) {
+            if (hideNavBarForKeyboard) {
                 window.setDecorFitsSystemWindows(false);
             }
         }
@@ -2366,9 +2367,7 @@
 
     public void setExtractView(View view) {
         mExtractFrame.removeAllViews();
-        mExtractFrame.addView(view, new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT));
+        mExtractFrame.addView(view, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
         mExtractView = view;
         if (view != null) {
             mExtractEditText = view.findViewById(
@@ -2387,7 +2386,7 @@
             mExtractAction = null;
         }
     }
-    
+
     /**
      * Replaces the current candidates view with a new one.  You only need to
      * call this when dynamically changing the view; normally, you should
@@ -2396,11 +2395,9 @@
      */
     public void setCandidatesView(View view) {
         mCandidatesFrame.removeAllViews();
-        mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT));
+        mCandidatesFrame.addView(view, new FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
     }
-    
+
     /**
      * Replaces the current input view with a new one.  You only need to
      * call this when dynamically changing the view; normally, you should
@@ -2409,12 +2406,10 @@
      */
     public void setInputView(View view) {
         mInputFrame.removeAllViews();
-        mInputFrame.addView(view, new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT));
+        mInputFrame.addView(view, new FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
         mInputView = view;
     }
-    
+
     /**
      * Called by the framework to create the layout for showing extracted text.
      * Only called when in fullscreen mode.  The returned view hierarchy must
@@ -3448,9 +3443,12 @@
         return false;
     }
 
+    /**
+     * Not implemented in this class.
+     */
     public void onAppPrivateCommand(String action, Bundle data) {
     }
-    
+
     /**
      * Handle a request by the system to toggle the soft input area.
      */
@@ -4092,11 +4090,6 @@
                 | (isInputViewShown() ? IME_VISIBLE : 0);
     }
 
-    private boolean isAutomotive() {
-        return getApplicationContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_AUTOMOTIVE);
-    }
-
     /**
      * Performs a dump of the InputMethodService's internal state.  Override
      * to add your own information to the dump.
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index c01664e..8be4c58 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -237,7 +237,7 @@
                 mNavigationBarFrame.setOnApplyWindowInsetsListener((view, insets) -> {
                     if (mNavigationBarFrame != null) {
                         boolean visible = insets.isVisible(captionBar());
-                        mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+                        mNavigationBarFrame.setVisibility(visible ? View.VISIBLE : View.GONE);
                     }
                     return view.onApplyWindowInsets(insets);
                 });
diff --git a/location/java/android/location/GeocoderParams.java b/core/java/android/location/GeocoderParams.java
similarity index 100%
rename from location/java/android/location/GeocoderParams.java
rename to core/java/android/location/GeocoderParams.java
diff --git a/location/java/android/location/Geofence.java b/core/java/android/location/Geofence.java
similarity index 100%
rename from location/java/android/location/Geofence.java
rename to core/java/android/location/Geofence.java
diff --git a/location/java/android/location/GnssSignalQuality.java b/core/java/android/location/GnssSignalQuality.java
similarity index 100%
rename from location/java/android/location/GnssSignalQuality.java
rename to core/java/android/location/GnssSignalQuality.java
diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/core/java/android/location/IFusedGeofenceHardware.aidl
similarity index 100%
rename from location/java/android/location/IFusedGeofenceHardware.aidl
rename to core/java/android/location/IFusedGeofenceHardware.aidl
diff --git a/location/java/android/location/IGpsGeofenceHardware.aidl b/core/java/android/location/IGpsGeofenceHardware.aidl
similarity index 100%
rename from location/java/android/location/IGpsGeofenceHardware.aidl
rename to core/java/android/location/IGpsGeofenceHardware.aidl
diff --git a/location/java/android/location/Location.aidl b/core/java/android/location/Location.aidl
similarity index 100%
rename from location/java/android/location/Location.aidl
rename to core/java/android/location/Location.aidl
diff --git a/location/java/android/location/Location.java b/core/java/android/location/Location.java
similarity index 98%
rename from location/java/android/location/Location.java
rename to core/java/android/location/Location.java
index 0eb657a..fd3e5a2 100644
--- a/location/java/android/location/Location.java
+++ b/core/java/android/location/Location.java
@@ -709,11 +709,9 @@
     /**
      * Returns the Mean Sea Level altitude of this location in meters.
      *
-     * @throws IllegalStateException if {@link #hasMslAltitude()} is false.
+     * <p>This is only valid if {@link #hasMslAltitude()} is true.
      */
     public @FloatRange double getMslAltitudeMeters() {
-        Preconditions.checkState(hasMslAltitude(),
-                "The Mean Sea Level altitude of this location is not set.");
         return mMslAltitudeMeters;
     }
 
@@ -744,11 +742,9 @@
      * percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
      * altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
      *
-     * @throws IllegalStateException if {@link #hasMslAltitudeAccuracy()} is false.
+     * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
      */
     public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
-        Preconditions.checkState(hasMslAltitudeAccuracy(),
-                "The Mean Sea Level altitude accuracy of this location is not set.");
         return mMslAltitudeAccuracyMeters;
     }
 
diff --git a/location/java/android/location/LocationTime.java b/core/java/android/location/LocationTime.java
similarity index 100%
rename from location/java/android/location/LocationTime.java
rename to core/java/android/location/LocationTime.java
diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java
index 7a153ef..c5f5614 100644
--- a/core/java/android/os/AggregateBatteryConsumer.java
+++ b/core/java/android/os/AggregateBatteryConsumer.java
@@ -116,8 +116,9 @@
      * Builder for DeviceBatteryConsumer.
      */
     public static final class Builder extends BaseBuilder<AggregateBatteryConsumer.Builder> {
-        public Builder(BatteryConsumer.BatteryConsumerData data, int scope) {
-            super(data, CONSUMER_TYPE_AGGREGATE);
+        public Builder(BatteryConsumer.BatteryConsumerData data, int scope,
+                double minConsumedPowerThreshold) {
+            super(data, CONSUMER_TYPE_AGGREGATE, minConsumedPowerThreshold);
             data.putInt(COLUMN_INDEX_SCOPE, scope);
         }
 
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index 0ba8d51..ca84b35 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -795,11 +795,12 @@
         protected final BatteryConsumer.BatteryConsumerData mData;
         protected final PowerComponents.Builder mPowerComponentsBuilder;
 
-        public BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType) {
+        public BaseBuilder(BatteryConsumer.BatteryConsumerData data, int consumerType,
+                double minConsumedPowerThreshold) {
             mData = data;
             data.putLong(COLUMN_INDEX_BATTERY_CONSUMER_TYPE, consumerType);
 
-            mPowerComponentsBuilder = new PowerComponents.Builder(data);
+            mPowerComponentsBuilder = new PowerComponents.Builder(data, minConsumedPowerThreshold);
         }
 
         @Nullable
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 7586bf7..a5f8844 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -707,7 +707,7 @@
                         XML_ATTR_PREFIX_INCLUDES_PROC_STATE_DATA, false);
 
                 builder = new Builder(customComponentNames.toArray(new String[0]), true,
-                        includesProcStateData);
+                        includesProcStateData, 0);
 
                 builder.setStatsStartTimestamp(
                         parser.getAttributeLong(null, XML_ATTR_START_TIMESTAMP));
@@ -782,6 +782,7 @@
         private final String[] mCustomPowerComponentNames;
         private final boolean mIncludePowerModels;
         private final boolean mIncludesProcessStateData;
+        private final double mMinConsumedPowerThreshold;
         private final BatteryConsumer.BatteryConsumerDataLayout mBatteryConsumerDataLayout;
         private long mStatsStartTimestampMs;
         private long mStatsEndTimestampMs;
@@ -802,11 +803,11 @@
         private BatteryStatsHistory mBatteryStatsHistory;
 
         public Builder(@NonNull String[] customPowerComponentNames) {
-            this(customPowerComponentNames, false, false);
+            this(customPowerComponentNames, false, false, 0);
         }
 
         public Builder(@NonNull String[] customPowerComponentNames, boolean includePowerModels,
-                boolean includeProcessStateData) {
+                boolean includeProcessStateData, double minConsumedPowerThreshold) {
             mBatteryConsumersCursorWindow =
                     new CursorWindow(null, BATTERY_CONSUMER_CURSOR_WINDOW_SIZE);
             mBatteryConsumerDataLayout =
@@ -817,12 +818,14 @@
             mCustomPowerComponentNames = customPowerComponentNames;
             mIncludePowerModels = includePowerModels;
             mIncludesProcessStateData = includeProcessStateData;
+            mMinConsumedPowerThreshold = minConsumedPowerThreshold;
             for (int scope = 0; scope < AGGREGATE_BATTERY_CONSUMER_SCOPE_COUNT; scope++) {
                 final BatteryConsumer.BatteryConsumerData data =
                         BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
                                 mBatteryConsumerDataLayout);
                 mAggregateBatteryConsumersBuilders[scope] =
-                        new AggregateBatteryConsumer.Builder(data, scope);
+                        new AggregateBatteryConsumer.Builder(
+                                data, scope, mMinConsumedPowerThreshold);
             }
         }
 
@@ -961,7 +964,8 @@
                 final BatteryConsumer.BatteryConsumerData data =
                         BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
                                 mBatteryConsumerDataLayout);
-                builder = new UidBatteryConsumer.Builder(data, batteryStatsUid);
+                builder = new UidBatteryConsumer.Builder(data, batteryStatsUid,
+                        mMinConsumedPowerThreshold);
                 mUidBatteryConsumerBuilders.put(uid, builder);
             }
             return builder;
@@ -979,7 +983,7 @@
                 final BatteryConsumer.BatteryConsumerData data =
                         BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
                                 mBatteryConsumerDataLayout);
-                builder = new UidBatteryConsumer.Builder(data, uid);
+                builder = new UidBatteryConsumer.Builder(data, uid, mMinConsumedPowerThreshold);
                 mUidBatteryConsumerBuilders.put(uid, builder);
             }
             return builder;
@@ -996,7 +1000,7 @@
                 final BatteryConsumer.BatteryConsumerData data =
                         BatteryConsumer.BatteryConsumerData.create(mBatteryConsumersCursorWindow,
                                 mBatteryConsumerDataLayout);
-                builder = new UserBatteryConsumer.Builder(data, userId);
+                builder = new UserBatteryConsumer.Builder(data, userId, mMinConsumedPowerThreshold);
                 mUserBatteryConsumerBuilders.put(userId, builder);
             }
             return builder;
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index b3f4d98..49d7e8b 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -80,6 +80,7 @@
     private final long mMaxStatsAgeMs;
     private final long mFromTimestamp;
     private final long mToTimestamp;
+    private final double mMinConsumedPowerThreshold;
     private final @BatteryConsumer.PowerComponent int[] mPowerComponents;
 
     private BatteryUsageStatsQuery(@NonNull Builder builder) {
@@ -87,6 +88,7 @@
         mUserIds = builder.mUserIds != null ? builder.mUserIds.toArray()
                 : new int[]{UserHandle.USER_ALL};
         mMaxStatsAgeMs = builder.mMaxStatsAgeMs;
+        mMinConsumedPowerThreshold = builder.mMinConsumedPowerThreshold;
         mFromTimestamp = builder.mFromTimestamp;
         mToTimestamp = builder.mToTimestamp;
         mPowerComponents = builder.mPowerComponents;
@@ -137,6 +139,14 @@
     }
 
     /**
+     * Returns the minimal power component consumed power threshold. The small power consuming
+     * components will be reported as zero.
+     */
+    public double getMinConsumedPowerThreshold() {
+        return mMinConsumedPowerThreshold;
+    }
+
+    /**
      * Returns the exclusive lower bound of the stored snapshot timestamps that should be included
      * in the aggregation.  Ignored if {@link #getToTimestamp()} is zero.
      */
@@ -158,6 +168,7 @@
         mUserIds = new int[in.readInt()];
         in.readIntArray(mUserIds);
         mMaxStatsAgeMs = in.readLong();
+        mMinConsumedPowerThreshold = in.readDouble();
         mFromTimestamp = in.readLong();
         mToTimestamp = in.readLong();
         mPowerComponents = in.createIntArray();
@@ -169,6 +180,7 @@
         dest.writeInt(mUserIds.length);
         dest.writeIntArray(mUserIds);
         dest.writeLong(mMaxStatsAgeMs);
+        dest.writeDouble(mMinConsumedPowerThreshold);
         dest.writeLong(mFromTimestamp);
         dest.writeLong(mToTimestamp);
         dest.writeIntArray(mPowerComponents);
@@ -202,6 +214,7 @@
         private long mMaxStatsAgeMs = DEFAULT_MAX_STATS_AGE_MS;
         private long mFromTimestamp;
         private long mToTimestamp;
+        private double mMinConsumedPowerThreshold = 0;
         private @BatteryConsumer.PowerComponent int[] mPowerComponents;
 
         /**
@@ -301,5 +314,14 @@
             mMaxStatsAgeMs = maxStatsAgeMs;
             return this;
         }
+
+        /**
+         * Set the minimal power component consumed power threshold. The small power consuming
+         * components will be reported as zero.
+         */
+        public Builder setMinConsumedPowerThreshold(double minConsumedPowerThreshold) {
+            mMinConsumedPowerThreshold = minConsumedPowerThreshold;
+            return this;
+        }
     }
 }
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index 0456a33..f10467f 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -127,6 +128,13 @@
     public static final int BUGREPORT_MODE_ONBOARDING = IDumpstate.BUGREPORT_MODE_ONBOARDING;
 
     /**
+     * The maximum value of supported bugreport mode.
+     * @hide
+     */
+    @TestApi
+    public static final int BUGREPORT_MODE_MAX_VALUE = BUGREPORT_MODE_ONBOARDING;
+
+    /**
      * Defines acceptable flags for customizing bugreport requests.
      * @hide
      */
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index ed14652..1a3dcee 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -126,50 +126,65 @@
     /**
      * Returns true if IP forwarding is enabled
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Use {@code android.net.INetd#ipfwdEnabled}")
     boolean getIpForwardingEnabled();
 
     /**
      * Enables/Disables IP Forwarding
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Avoid using this directly. Instead, enable tethering with "
+            + "{@code android.net.TetheringManager#startTethering}. See also "
+            + "{@code INetd#ipfwdEnableForwarding(String)}.")
     void setIpForwardingEnabled(boolean enabled);
 
     /**
      * Start tethering services with the specified dhcp server range
      * arg is a set of start end pairs defining the ranges.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "{@code android.net.TetheringManager#startTethering}")
     void startTethering(in String[] dhcpRanges);
 
     /**
      * Stop currently running tethering services
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "{@code android.net.TetheringManager#stopTethering(int)}")
     void stopTethering();
 
     /**
      * Returns true if tethering services are started
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Generally track your own tethering requests. "
+            + "See also {@code android.net.INetd#tetherIsEnabled()}")
     boolean isTetheringStarted();
 
     /**
      * Tethers the specified interface
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Avoid using this directly. Instead, enable tethering with "
+            + "{@code android.net.TetheringManager#startTethering}. See also "
+            + "{@code com.android.net.module.util.NetdUtils#tetherInterface}.")
     void tetherInterface(String iface);
 
     /**
      * Untethers the specified interface
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Avoid using this directly. Instead, disable "
+            + "tethering with {@code android.net.TetheringManager#stopTethering(int)}. "
+            + "See also {@code NetdUtils#untetherInterface}.")
     void untetherInterface(String iface);
 
     /**
      * Returns a list of currently tethered interfaces
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "{@code android.net.TetheringManager#getTetheredIfaces()}")
     String[] listTetheredInterfaces();
 
     /**
@@ -177,13 +192,17 @@
      *  The address and netmask of the external interface is used for
      *  the NAT'ed network.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Avoid using this directly. Instead, enable tethering with "
+            + "{@code android.net.TetheringManager#startTethering}.")
     void enableNat(String internalInterface, String externalInterface);
 
     /**
      *  Disables Network Address Translation between two interfaces.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
+            publicAlternatives = "Avoid using this directly. Instead, disable tethering with "
+            + "{@code android.net.TetheringManager#stopTethering(int)}.")
     void disableNat(String internalInterface, String externalInterface);
 
     /**
diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl
index 6275352..f30dd20 100644
--- a/core/java/android/os/IVibratorManagerService.aidl
+++ b/core/java/android/os/IVibratorManagerService.aidl
@@ -36,4 +36,10 @@
     void vibrate(int uid, int displayId, String opPkg, in CombinedVibration vibration,
             in VibrationAttributes attributes, String reason, IBinder token);
     void cancelVibrate(int usageFilter, IBinder token);
+
+    // Async oneway APIs.
+    // There is no order guarantee with respect to the two-way APIs above like
+    // vibrate/isVibrating/cancel.
+    oneway void performHapticFeedback(int uid, int displayId, String opPkg, int constant,
+            boolean always, String reason, IBinder token);
 }
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 5dffa0a..9e5f539 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -461,9 +461,11 @@
         private static final byte POWER_MODEL_UNINITIALIZED = -1;
 
         private final BatteryConsumer.BatteryConsumerData mData;
+        private final double mMinConsumedPowerThreshold;
 
-        Builder(BatteryConsumer.BatteryConsumerData data) {
+        Builder(BatteryConsumer.BatteryConsumerData data, double minConsumedPowerThreshold) {
             mData = data;
+            mMinConsumedPowerThreshold = minConsumedPowerThreshold;
             for (BatteryConsumer.Key[] keys : mData.layout.keys) {
                 for (BatteryConsumer.Key key : keys) {
                     if (key.mPowerModelColumnIndex != -1) {
@@ -476,6 +478,9 @@
         @NonNull
         public Builder setConsumedPower(BatteryConsumer.Key key, double componentPower,
                 int powerModel) {
+            if (Math.abs(componentPower) < mMinConsumedPowerThreshold) {
+                componentPower = 0;
+            }
             mData.putDouble(key.mPowerColumnIndex, componentPower);
             if (key.mPowerModelColumnIndex != -1) {
                 mData.putInt(key.mPowerModelColumnIndex, powerModel);
@@ -491,6 +496,9 @@
          */
         @NonNull
         public Builder setConsumedPowerForCustomComponent(int componentId, double componentPower) {
+            if (Math.abs(componentPower) < mMinConsumedPowerThreshold) {
+                componentPower = 0;
+            }
             final int index = componentId - BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID;
             if (index < 0 || index >= mData.layout.customPowerComponentCount) {
                 throw new IllegalArgumentException(
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 1cd0f3b..04c257b 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -206,6 +206,15 @@
     }
 
     @Override
+    public void performHapticFeedback(int constant, boolean always, String reason) {
+        if (mVibratorManager == null) {
+            Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager.");
+            return;
+        }
+        mVibratorManager.performHapticFeedback(constant, always, reason);
+    }
+
+    @Override
     public void cancel() {
         if (mVibratorManager == null) {
             Log.w(TAG, "Failed to cancel vibrate; no vibrator manager.");
diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java
index 284b246..ee90834 100644
--- a/core/java/android/os/SystemVibratorManager.java
+++ b/core/java/android/os/SystemVibratorManager.java
@@ -145,6 +145,21 @@
     }
 
     @Override
+    public void performHapticFeedback(int constant, boolean always, String reason) {
+        if (mService == null) {
+            Log.w(TAG, "Failed to perform haptic feedback; no vibrator manager service.");
+            return;
+        }
+        try {
+            mService.performHapticFeedback(
+                    Process.myUid(), mContext.getAssociatedDisplayId(), mPackageName, constant,
+                    always, reason, mToken);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to perform haptic feedback.", e);
+        }
+    }
+
+    @Override
     public void cancel() {
         cancelVibration(VibrationAttributes.USAGE_FILTER_MATCH_ALL);
     }
@@ -228,6 +243,11 @@
         }
 
         @Override
+        public void performHapticFeedback(int effectId, boolean always, String reason) {
+            SystemVibratorManager.this.performHapticFeedback(effectId, always, reason);
+        }
+
+        @Override
         public void cancel() {
             SystemVibratorManager.this.cancel();
         }
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 103452d..03a1b6f 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -207,17 +207,18 @@
         private String mPackageWithHighestDrain = PACKAGE_NAME_UNINITIALIZED;
         private boolean mExcludeFromBatteryUsageStats;
 
-        public Builder(BatteryConsumerData data, @NonNull BatteryStats.Uid batteryStatsUid) {
-            this(data, batteryStatsUid, batteryStatsUid.getUid());
+        public Builder(BatteryConsumerData data, @NonNull BatteryStats.Uid batteryStatsUid,
+                double minConsumedPowerThreshold) {
+            this(data, batteryStatsUid, batteryStatsUid.getUid(), minConsumedPowerThreshold);
         }
 
-        public Builder(BatteryConsumerData data, int uid) {
-            this(data, null, uid);
+        public Builder(BatteryConsumerData data, int uid, double minConsumedPowerThreshold) {
+            this(data, null, uid, minConsumedPowerThreshold);
         }
 
         private Builder(BatteryConsumerData data, @Nullable BatteryStats.Uid batteryStatsUid,
-                int uid) {
-            super(data, CONSUMER_TYPE_UID);
+                int uid, double minConsumedPowerThreshold) {
+            super(data, CONSUMER_TYPE_UID, minConsumedPowerThreshold);
             mBatteryStatsUid = batteryStatsUid;
             mUid = uid;
             mIsVirtualUid = mUid == Process.SDK_SANDBOX_VIRTUAL_UID;
diff --git a/core/java/android/os/UserBatteryConsumer.java b/core/java/android/os/UserBatteryConsumer.java
index 6b4a5cf..a2ff078 100644
--- a/core/java/android/os/UserBatteryConsumer.java
+++ b/core/java/android/os/UserBatteryConsumer.java
@@ -107,8 +107,8 @@
     public static final class Builder extends BaseBuilder<Builder> {
         private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
 
-        Builder(BatteryConsumerData data, int userId) {
-            super(data, CONSUMER_TYPE_USER);
+        Builder(BatteryConsumerData data, int userId, double minConsumedPowerThreshold) {
+            super(data, CONSUMER_TYPE_USER, minConsumedPowerThreshold);
             data.putLong(COLUMN_INDEX_USER_ID, userId);
         }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index bcde31a..c6cb604 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1002,6 +1002,24 @@
     public static final String DISALLOW_ADD_CLONE_PROFILE = "no_add_clone_profile";
 
     /**
+     * Specifies if a user is disallowed from creating a private profile.
+     * <p>The default value for an unmanaged user is <code>false</code>.
+     * For users with a device owner set, the default is <code>true</code>.
+     *
+     * <p>Holders of the permission
+     * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILES}
+     * can set this restriction using the DevicePolicyManager APIs mentioned below.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     * @hide
+     */
+    public static final String DISALLOW_ADD_PRIVATE_PROFILE = "no_add_private_profile";
+
+    /**
      * Specifies if a user is disallowed from disabling application verification. The default
      * value is <code>false</code>.
      *
@@ -1895,6 +1913,7 @@
             DISALLOW_ADD_USER,
             DISALLOW_ADD_MANAGED_PROFILE,
             DISALLOW_ADD_CLONE_PROFILE,
+            DISALLOW_ADD_PRIVATE_PROFILE,
             ENSURE_VERIFY_APPS,
             DISALLOW_CONFIG_CELL_BROADCASTS,
             DISALLOW_CONFIG_MOBILE_NETWORKS,
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index aafa501..99c9925 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -510,6 +510,28 @@
             String reason, @NonNull VibrationAttributes attributes);
 
     /**
+     * Performs a haptic feedback.
+     *
+     * <p>A haptic feedback is a short vibration feedback. The type of feedback is identified via
+     * the {@code constant}, which should be one of the effect constants provided in
+     * {@link HapticFeedbackConstants}. The haptic feedback provided for a given effect ID is
+     * consistent across all usages on the same device.
+     *
+     * @param constant the ID for the haptic feedback. This should be one of the constants defined
+     *          in {@link HapticFeedbackConstants}.
+     * @param always {@code true} if the haptic feedback should be played regardless of the user
+     *          vibration intensity settings applicable to the corresponding vibration.
+     *          {@code false} if the vibration for the haptic feedback should respect the applicable
+     *          vibration intensity settings.
+     * @param reason the reason for this haptic feedback.
+     *
+     * @hide
+     */
+    public void performHapticFeedback(int constant, boolean always, String reason) {
+        Log.w(TAG, "performHapticFeedback is not supported");
+    }
+
+    /**
      * Query whether the vibrator natively supports the given effects.
      *
      * <p>If an effect is not supported, the system may still automatically fall back to playing
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index f506ef8..e0b6a9f 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -35,7 +35,8 @@
 public abstract class VibratorManager {
     private static final String TAG = "VibratorManager";
 
-    private final String mPackageName;
+    /** @hide */
+    protected final String mPackageName;
 
     /**
      * @hide to prevent subclassing from outside of the framework
@@ -137,6 +138,21 @@
             String reason, @Nullable VibrationAttributes attributes);
 
     /**
+     * Performs a haptic feedback.
+     *
+     * @param constant the ID of the requested haptic feedback. Should be one of the constants
+     *          defined in {@link HapticFeedbackConstants}.
+     * @param always {@code true} if the haptic feedback should be played regardless of the user
+     *          vibration intensity settings applicable to the corresponding vibration.
+     *          {@code false} otherwise.
+     * @param reason the reason for this haptic feedback.
+     * @hide
+     */
+    public void performHapticFeedback(int constant, boolean always, String reason) {
+        Log.w(TAG, "performHapticFeedback is not supported");
+    }
+
+    /**
      * Turn all the vibrators off.
      */
     @RequiresPermission(android.Manifest.permission.VIBRATE)
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
new file mode 100644
index 0000000..851aa6d
--- /dev/null
+++ b/core/java/android/os/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.os"
+
+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"
+}
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 22e8251..8961846 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -20,8 +20,11 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.pm.UserInfo;
+import android.os.IInstalld;
 import android.os.IVold;
+import android.os.ParcelFileDescriptor;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.Set;
 
@@ -185,4 +188,17 @@
     public abstract void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid,
             List<UserInfo> users);
 
+    /**
+     * A proxy call to the corresponding method in Installer.
+     * @see com.android.server.pm.Installer#createFsveritySetupAuthToken()
+     */
+    public abstract IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken(
+            ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException;
+
+    /**
+     * A proxy call to the corresponding method in Installer.
+     * @see com.android.server.pm.Installer#enableFsverity()
+     */
+    public abstract int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath,
+            String packageName) throws IOException;
 }
diff --git a/core/java/android/os/vibrator/flags.aconfig b/core/java/android/os/vibrator/flags.aconfig
new file mode 100644
index 0000000..c01ef3d
--- /dev/null
+++ b/core/java/android/os/vibrator/flags.aconfig
@@ -0,0 +1,15 @@
+package: "android.os.vibrator"
+
+flag {
+    namespace: "haptics"
+    name: "use_vibrator_haptic_feedback"
+    description: "Enables performHapticFeedback to directly use the vibrator service instead of going through the window session"
+    bug: "295459081"
+}
+
+flag {
+    namespace: "haptics"
+    name: "haptics_customization_enabled"
+    description: "Enables the haptics customization feature"
+    bug: "241918098"
+}
\ No newline at end of file
diff --git a/core/java/android/os/vibrator/persistence/ParsedVibration.java b/core/java/android/os/vibrator/persistence/ParsedVibration.java
index a76f597..ded74ea 100644
--- a/core/java/android/os/vibrator/persistence/ParsedVibration.java
+++ b/core/java/android/os/vibrator/persistence/ParsedVibration.java
@@ -70,7 +70,7 @@
     @TestApi
     @VisibleForTesting
     @NonNull
-    public List<VibrationEffect> getVibrationEffectListForTesting() {
+    public List<VibrationEffect> getVibrationEffects() {
         return Collections.unmodifiableList(mEffects);
     }
 
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 2a4c01e1..1f798ba 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -87,11 +87,6 @@
             "location_indicators_enabled";
 
     /**
-     * Whether to show the Permissions Hub.
-     */
-    private static final String PROPERTY_PERMISSIONS_HUB_2_ENABLED = "permissions_hub_2_enabled";
-
-    /**
      * How long after an access to show it as "recent"
      */
     private static final String RECENT_ACCESS_TIME_MS = "recent_access_time_ms";
@@ -106,14 +101,9 @@
     private static final long DEFAULT_RUNNING_TIME_MS = 5000L;
     private static final long DEFAULT_RECENT_TIME_MS = 15000L;
 
-    private static boolean shouldShowPermissionsHub() {
-        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                PROPERTY_PERMISSIONS_HUB_2_ENABLED, false);
-    }
-
     private static boolean shouldShowIndicators() {
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                PROPERTY_CAMERA_MIC_ICONS_ENABLED, true) || shouldShowPermissionsHub();
+                PROPERTY_CAMERA_MIC_ICONS_ENABLED, true);
     }
 
     private static boolean shouldShowLocationIndicator() {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 522caac..f823dbc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2831,7 +2831,7 @@
     /** @hide - Private call() method to query the 'global' table */
     public static final String CALL_METHOD_LIST_GLOBAL = "LIST_global";
 
-    /** @hide - Private call() method to reset to defaults the 'configuration' table */
+    /** @hide - Private call() method to query the 'configuration' table */
     public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
 
     /** @hide - Private call() method to disable / re-enable syncs to the 'configuration' table */
@@ -4871,13 +4871,13 @@
         public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
 
         /**
-         * Control whether to stay awake on fold
+         * Control lock behavior on fold
          *
          * If this isn't set, the system falls back to a device specific default.
          * @hide
          */
         @Readable
-        public static final String STAY_AWAKE_ON_FOLD = "stay_awake_on_fold";
+        public static final String FOLD_LOCK_BEHAVIOR = "fold_lock_behavior_setting";
 
         /**
          * The amount of time in milliseconds before the device goes to sleep or begins
@@ -5885,15 +5885,6 @@
         public static final String MULTI_AUDIO_FOCUS_ENABLED = "multi_audio_focus_enabled";
 
         /**
-         * Whether desktop mode is enabled or not.
-         * 0 = off
-         * 1 = on
-         * @hide
-         */
-        @Readable
-        public static final String DESKTOP_MODE = "desktop_mode";
-
-        /**
          * The information of locale preference. This records user's preference to avoid
          * unsynchronized and existing locale preference in
          * {@link Locale#getDefault(Locale.Category)}.
@@ -6066,7 +6057,6 @@
             PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT);
             PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE);
             PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE_VENDOR_HINT);
-            PRIVATE_SETTINGS.add(DESKTOP_MODE);
             PRIVATE_SETTINGS.add(LOCALE_PREFERENCES);
             PRIVATE_SETTINGS.add(TOUCHPAD_POINTER_SPEED);
             PRIVATE_SETTINGS.add(TOUCHPAD_NATURAL_SCROLLING);
@@ -10674,20 +10664,6 @@
                 "search_press_hold_nav_handle_enabled";
 
         /**
-         * Control whether Trust Agents are in active unlock or extend unlock mode.
-         * @hide
-         */
-        @Readable
-        public static final String TRUST_AGENTS_EXTEND_UNLOCK = "trust_agents_extend_unlock";
-
-        /**
-         * Control whether the screen locks when trust is lost.
-         * @hide
-         */
-        @Readable
-        public static final String LOCK_SCREEN_WHEN_TRUST_LOST = "lock_screen_when_trust_lost";
-
-        /**
          * Control whether Night display is currently activated.
          * @hide
          */
@@ -18370,24 +18346,28 @@
              * If hotword detection should be enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String HOTWORD_DETECTION_ENABLED = "hotword_detection_enabled";
 
             /**
              * Whether Smart Replies are enabled within Wear.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SMART_REPLIES_ENABLED = "smart_replies_enabled";
 
             /**
              * The default vibration pattern.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String DEFAULT_VIBRATION = "default_vibration";
 
             /**
              * If FLP should obtain location data from the paired device.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String OBTAIN_PAIRED_DEVICE_LOCATION =
                     "obtain_paired_device_location";
 
@@ -18395,6 +18375,7 @@
              * The play store availability on companion phone.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String PHONE_PLAY_STORE_AVAILABILITY =
                     "phone_play_store_availability";
 
@@ -18410,6 +18391,7 @@
              * Whether the bug report is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BUG_REPORT = "bug_report";
 
             // Possible bug report states
@@ -18422,12 +18404,14 @@
              * The enabled/disabled state of the SmartIlluminate.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SMART_ILLUMINATE_ENABLED = "smart_illuminate_enabled";
 
             /**
              * Whether automatic time is enabled on the watch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_AUTO_TIME = "clockwork_auto_time";
 
             // Possible clockwork auto time states
@@ -18445,6 +18429,7 @@
              * Whether automatic time zone is enabled on the watch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_AUTO_TIME_ZONE = "clockwork_auto_time_zone";
 
             // Possible clockwork auto time zone states
@@ -18461,12 +18446,14 @@
              * Whether 24 hour time format is enabled on the watch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_24HR_TIME = "clockwork_24hr_time";
 
             /**
              * Whether the auto wifi toggle setting is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AUTO_WIFI = "auto_wifi";
 
             // Possible force wifi on states
@@ -18486,6 +18473,7 @@
              * wifi requirement until this time). The time is in millis since epoch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS =
                     "alt_bypass_wifi_requirement_time_millis";
 
@@ -18493,6 +18481,7 @@
              * Whether the setup was skipped.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SETUP_SKIPPED = "setup_skipped";
 
             // Possible setup_skipped states
@@ -18507,6 +18496,7 @@
              * The last requested call forwarding action.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String LAST_CALL_FORWARD_ACTION = "last_call_forward_action";
 
             // Possible call forwarding actions
@@ -18519,22 +18509,31 @@
 
             // Stem button settings.
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_1_TYPE = "STEM_1_TYPE";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_1_DATA = "STEM_1_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_1_DEFAULT_DATA = "STEM_1_DEFAULT_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_2_TYPE = "STEM_2_TYPE";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_2_DATA = "STEM_2_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_2_DEFAULT_DATA = "STEM_2_DEFAULT_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_3_TYPE = "STEM_3_TYPE";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_3_DATA = "STEM_3_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_3_DEFAULT_DATA = "STEM_3_DEFAULT_DATA";
 
             // Stem types
@@ -18549,12 +18548,14 @@
              * If the device should be muted when off body.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String MUTE_WHEN_OFF_BODY_ENABLED = "obtain_mute_when_off_body";
 
             /**
              * Wear OS version string.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string";
 
             /**
@@ -18567,24 +18568,28 @@
              * The android wear system version.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String ANDROID_WEAR_VERSION = "android_wear_version";
 
             /**
              * The wear system capabiltiies.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SYSTEM_CAPABILITIES = "system_capabilities";
 
             /**
              * The android wear system edition.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SYSTEM_EDITION = "android_wear_system_edition";
 
             /**
              * The Wear platform MR number.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_PLATFORM_MR_NUMBER = "wear_platform_mr_number";
 
             /**
@@ -18598,36 +18603,42 @@
              * Whether ambient is currently enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_ENABLED = "ambient_enabled";
 
             /**
              * Whether ambient tilt to wake is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_TILT_TO_WAKE = "ambient_tilt_to_wake";
 
             /**
              * Whether ambient low bit mode is enabled by developer options.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_LOW_BIT_ENABLED_DEV = "ambient_low_bit_enabled_dev";
 
             /**
              * Whether ambient touch to wake is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_TOUCH_TO_WAKE = "ambient_touch_to_wake";
 
             /**
              * Whether ambient tilt to bright is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_TILT_TO_BRIGHT = "ambient_tilt_to_bright";
 
             /**
              * Whether touch and hold to edit WF is enabled
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED =
                     "gesture_touch_and_hold_watchface_enabled";
 
@@ -18641,6 +18652,7 @@
              * Whether bedtime mode is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BEDTIME_MODE = "bedtime_mode";
 
             /**
@@ -18652,31 +18664,35 @@
              * Whether the current watchface is decomposable.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String DECOMPOSABLE_WATCHFACE = "current_watchface_decomposable";
 
             /**
              * Whether to force ambient when docked.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_FORCE_WHEN_DOCKED = "ambient_force_when_docked";
 
             /**
              * Whether the ambient low bit mode is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_LOW_BIT_ENABLED = "ambient_low_bit_enabled";
 
             /**
              * The timeout duration in minutes of ambient mode when plugged in.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_PLUGGED_TIMEOUT_MIN = "ambient_plugged_timeout_min";
 
             /**
              * What OS does paired device has.
              * @hide
              */
-            @Readable
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String PAIRED_DEVICE_OS_TYPE = "paired_device_os_type";
 
             // Possible values of PAIRED_DEVICE_OS_TYPE
@@ -18709,6 +18725,7 @@
              * The user's last setting for hfp client.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String USER_HFP_CLIENT_SETTING = "user_hfp_client_setting";
 
             // Possible hfp client user setting values
@@ -18733,6 +18750,7 @@
              * The companion App name.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String COMPANION_APP_NAME = "wear_companion_app_name";
 
             /**
@@ -18740,18 +18758,21 @@
              * wear. 1 for supporting, 0 for not supporting.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String ENABLE_ALL_LANGUAGES = "enable_all_languages";
 
             /**
              * The Locale (as language tag) the user chose at startup.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SETUP_LOCALE = "setup_locale";
 
             /**
              * The version of oem setup present.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String OEM_SETUP_VERSION = "oem_setup_version";
 
             /**
@@ -18797,6 +18818,7 @@
              * -{@link BATTERY_SAVER_MODE_CUSTOM}
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BATTERY_SAVER_MODE = "battery_saver_mode";
 
             /**
@@ -18829,6 +18851,7 @@
              * The maximum ambient mode duration when an activity is allowed to auto resume.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS =
                     "wear_activity_auto_resume_timeout_ms";
 
@@ -18844,6 +18867,7 @@
              * If burn in protection is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection";
 
             /**
@@ -18862,6 +18886,7 @@
              *          RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3"
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode";
 
             /**
@@ -18900,6 +18925,7 @@
              *
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_SYSUI_PACKAGE = "clockwork_sysui_package";
 
             /**
@@ -18929,6 +18955,7 @@
              * Whether the device has Wet Mode/ Touch Lock Mode enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WET_MODE_ON = "wet_mode_on";
 
             /**
@@ -18947,6 +18974,7 @@
              * Whether charging sounds are enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CHARGING_SOUNDS_ENABLED = "wear_charging_sounds_enabled";
 
             /**
@@ -18955,6 +18983,7 @@
              *
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String DYNAMIC_COLOR_THEME_ENABLED = "dynamic_color_theme_enabled";
 
             /**
@@ -19046,6 +19075,7 @@
              * The key to indicate the data migration status on device upgrade in Wear Services.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String UPGRADE_DATA_MIGRATION_STATUS =
                     "upgrade_data_migration_status";
 
@@ -19096,17 +19126,20 @@
              * The custom foreground color.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CUSTOM_COLOR_FOREGROUND = "custom_foreground_color";
 
             /**
              * The custom background color.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CUSTOM_COLOR_BACKGROUND = "custom_background_color";
 
             /** The status of the phone switching process.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String PHONE_SWITCHING_STATUS = "phone_switching_status";
 
             /**
@@ -19187,6 +19220,7 @@
              * (0 = false, 1 = true)
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String REDUCE_MOTION = "reduce_motion";
 
             /**
@@ -19248,6 +19282,7 @@
              * Controls the launcher ui mode on wearable devices.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_LAUNCHER_UI_MODE = "wear_launcher_ui_mode";
 
             /** Whether Wear Power Anomaly Service is enabled.
@@ -19374,6 +19409,36 @@
         }
 
         /**
+         * Return all stored flags.
+         *
+         * The keys take the form {@code namespace/flag}, and the values are the flag values.
+         *
+         * @hide
+         */
+        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+        @NonNull
+        public static Map<String, String> getAllStrings() {
+            HashMap<String, String> allFlags = new HashMap<String, String>();
+            try {
+                ContentResolver resolver = getContentResolver();
+                Bundle arg = new Bundle();
+                arg.putInt(Settings.CALL_METHOD_USER_KEY, resolver.getUserId());
+                IContentProvider cp = sProviderHolder.getProvider(resolver);
+                Bundle b = cp.call(resolver.getAttributionSource(),
+                        sProviderHolder.mUri.getAuthority(), CALL_METHOD_LIST_CONFIG, null, arg);
+                if (b != null) {
+                    Map<String, String> flagsToValues =
+                            (HashMap) b.getSerializable(Settings.NameValueTable.VALUE,
+                                            java.util.HashMap.class);
+                    allFlags.putAll(flagsToValues);
+                }
+            } catch (RemoteException e) {
+                Log.w(TAG, "Can't query configuration table for " + CONTENT_URI, e);
+            }
+            return allFlags;
+        }
+
+        /**
          * Look up a list of names in the database, within the specified namespace.
          *
          * @param resolver to access the database with
diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java
index 266046e..132700d 100644
--- a/core/java/android/security/FileIntegrityManager.java
+++ b/core/java/android/security/FileIntegrityManager.java
@@ -16,12 +16,21 @@
 
 package android.security;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.os.IInstalld.IFsveritySetupAuthToken;
+import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.system.ErrnoException;
 
+import com.android.internal.security.VerityUtils;
+
+import java.io.File;
+import java.io.IOException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 
@@ -55,6 +64,67 @@
     }
 
     /**
+     * Enables fs-verity to the owned file under the calling app's private directory. It always uses
+     * the common configuration, i.e. SHA-256 digest algorithm, 4K block size, and without salt.
+     *
+     * The operation can only succeed when the file is not opened as writable by any process.
+     *
+     * It takes O(file size) time to build the underlying data structure for continuous
+     * verification. The operation is atomic, i.e. it's either enabled or not, even in case of
+     * power failure during or after the call.
+     *
+     * Note for the API users: When the file's authenticity is crucial, the app typical needs to
+     * perform a signature check by itself before using the file. The signature is often delivered
+     * as a separate file and stored next to the targeting file in the filesystem. The public key of
+     * the signer (normally the same app developer) can be put in the APK, and the app can use the
+     * public key to verify the signature to the file's actual fs-verity digest (from {@link
+     * #getFsVerityDigest}) before using the file. The exact format is not prescribed by the
+     * framework. App developers may choose to use common practices like JCA for the signing and
+     * verification, or their own preferred approach.
+     *
+     * @param file The file to enable fs-verity. It should be an absolute path.
+     *
+     * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a>
+     */
+    @FlaggedApi(Flags.FLAG_FSVERITY_API)
+    public void setupFsVerity(@NonNull File file) throws IOException {
+        if (!file.isAbsolute()) {
+            throw new IllegalArgumentException("Expect an absolute path");
+        }
+        IFsveritySetupAuthToken authToken;
+        // fs-verity setup requires no writable fd to the file. Make sure it's closed before
+        // continue.
+        try (var authFd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE)) {
+            authToken = mService.createAuthToken(authFd);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        try {
+            int errno = mService.setupFsverity(authToken, file.getPath(),
+                    mContext.getPackageName());
+            if (errno != 0) {
+                new ErrnoException("setupFsVerity", errno).rethrowAsIOException();
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns the fs-verity digest for the owned file under the calling app's
+     * private directory, or null when the file does not have fs-verity enabled.
+     *
+     * @param file The file to measure the fs-verity digest.
+     * @return The fs-verity digeset in byte[], null if none.
+     * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a>
+     */
+    @FlaggedApi(Flags.FLAG_FSVERITY_API)
+    public @Nullable byte[] getFsVerityDigest(@NonNull File file) throws IOException {
+        return VerityUtils.getFsverityDigest(file.getPath());
+    }
+
+    /**
      * Returns whether the given certificate can be used to prove app's install source. Always
      * return false if the feature is not supported.
      *
diff --git a/core/java/android/security/IFileIntegrityService.aidl b/core/java/android/security/IFileIntegrityService.aidl
index dff347e..1a6cf88 100644
--- a/core/java/android/security/IFileIntegrityService.aidl
+++ b/core/java/android/security/IFileIntegrityService.aidl
@@ -16,6 +16,9 @@
 
 package android.security;
 
+import android.os.ParcelFileDescriptor;
+import android.os.IInstalld;
+
 /**
  * Binder interface to communicate with FileIntegrityService.
  * @hide
@@ -23,4 +26,8 @@
 interface IFileIntegrityService {
     boolean isApkVeritySupported();
     boolean isAppSourceCertificateTrusted(in byte[] certificateBytes, in String packageName);
+
+    IInstalld.IFsveritySetupAuthToken createAuthToken(in ParcelFileDescriptor authFd);
+    int setupFsverity(IInstalld.IFsveritySetupAuthToken authToken, in String filePath,
+            in String packageName);
 }
diff --git a/core/java/android/security/OWNERS b/core/java/android/security/OWNERS
index 22b1f02..96c0be7 100644
--- a/core/java/android/security/OWNERS
+++ b/core/java/android/security/OWNERS
@@ -6,4 +6,5 @@
 
 per-file *NetworkSecurityPolicy.java = file:net/OWNERS
 per-file Confirmation*.java = file:/keystore/OWNERS
-per-file FileIntegrityManager.java = victorhsieh@google.com
+per-file FileIntegrityManager.java = file:platform/system/security:/fsverity/OWNERS
+per-file IFileIntegrityService.aidl = file:platform/system/security:/fsverity/OWNERS
diff --git a/core/java/android/service/credentials/Action.java b/core/java/android/service/credentials/Action.java
index 55133ae..9b1132a 100644
--- a/core/java/android/service/credentials/Action.java
+++ b/core/java/android/service/credentials/Action.java
@@ -46,7 +46,14 @@
      * <p> See details on usage of {@code Action} for various actionable entries in
      * {@link BeginCreateCredentialResponse} and {@link BeginGetCredentialResponse}.
      *
-     * @param slice the display content to be displayed on the UI, along with this action
+     * @param slice the slice containing the metadata to be shown on the UI, must be constructed
+     *              through the {@link androidx.credentials.provider} Jetpack library;
+     *              If constructed manually, the {@code slice} object must
+     *              contain the non-null properties of the
+     *              {@link androidx.credentials.provider.Action} class populated as slice items
+     *              against specific hints as used in the class's {@code toSlice} method,
+     *              since the Android System uses this library to parse the {@code slice} and
+     *              extract the required attributes
      */
     public Action(@NonNull Slice slice) {
         Objects.requireNonNull(slice, "slice must not be null");
diff --git a/core/java/android/service/credentials/CreateEntry.java b/core/java/android/service/credentials/CreateEntry.java
index 6a9f09f..2495c7d 100644
--- a/core/java/android/service/credentials/CreateEntry.java
+++ b/core/java/android/service/credentials/CreateEntry.java
@@ -66,7 +66,14 @@
     /**
      * Constructs a CreateEntry to be displayed on the UI.
      *
-     * @param slice the display content to be displayed on the UI, along with this entry
+     * @param slice the slice containing the metadata to be shown on the UI, must be constructed
+     *              through the {@link androidx.credentials.provider} Jetpack library;
+     *              If constructed manually, the {@code slice} object must
+     *              contain the non-null properties of the
+     *              {@link androidx.credentials.provider.CreateEntry} class populated as slice items
+     *              against specific hints as used in the class's {@code toSlice} method,
+     *              since the Android System uses this library to parse the {@code slice} and
+     *              extract the required attributes
      */
     public CreateEntry(
             @NonNull Slice slice) {
diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java
index 512d833..53094e8 100644
--- a/core/java/android/service/credentials/CredentialEntry.java
+++ b/core/java/android/service/credentials/CredentialEntry.java
@@ -69,8 +69,14 @@
      *                                   receive the complete corresponding
      *                                   {@link GetCredentialRequest}.
      * @param type the type of the credential for which this credential entry is being created
-     * @param slice the slice containing the metadata to be shown on the UI. Must be
-     *              constructed through the androidx.credentials jetpack library.
+     * @param slice the slice containing the metadata to be shown on the UI, must be constructed
+     *              through the {@link androidx.credentials.provider} Jetpack library;
+     *              If constructed manually, the {@code slice} object must
+     *              contain the non-null properties of the
+     *              {@link androidx.credentials.provider.CredentialEntry} class populated as slice
+     *              items against specific hints as used in the class's {@code toSlice} method,
+     *              since the Android System uses this library to parse the {@code slice} and
+     *              extract the required attributes
      *
      * @throws IllegalArgumentException If {@code beginGetCredentialOptionId} or {@code type}
      * is null, or empty
diff --git a/core/java/android/service/credentials/RemoteEntry.java b/core/java/android/service/credentials/RemoteEntry.java
index 5b3218a..5fd9925 100644
--- a/core/java/android/service/credentials/RemoteEntry.java
+++ b/core/java/android/service/credentials/RemoteEntry.java
@@ -73,7 +73,14 @@
     /**
      * Constructs a RemoteEntry to be displayed on the UI.
      *
-     * @param slice the display content to be displayed on the UI, along with this entry
+     * @param slice the slice containing the metadata to be shown on the UI, must be constructed
+     *              through the {@link androidx.credentials.provider} Jetpack library;
+     *              If constructed manually, the {@code slice} object must
+     *              contain the non-null properties of the
+     *              {@link androidx.credentials.provider.RemoteEntry} class populated as slice items
+     *              against specific hints as used in the class's {@code toSlice} method,
+     *              since the Android System uses this library to parse the {@code slice} and
+     *              extract the required attributes
      */
     public RemoteEntry(
             @NonNull Slice slice) {
diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS
index 489a5f6..77bcee8 100644
--- a/core/java/android/service/dreams/OWNERS
+++ b/core/java/android/service/dreams/OWNERS
@@ -4,5 +4,7 @@
 dsandler@google.com
 galinap@google.com
 jjaggi@google.com
+lusilva@google.com
 michaelwr@google.com
 santoscordon@google.com
+wxyz@google.com
diff --git a/core/java/android/service/trust/OWNERS b/core/java/android/service/trust/OWNERS
index a895f7f..d352525 100644
--- a/core/java/android/service/trust/OWNERS
+++ b/core/java/android/service/trust/OWNERS
@@ -1,4 +1,4 @@
 # Bug component: 36824
 
-cbrubaker@google.com
 jacobhobbie@google.com
+dlm@google.com
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java b/core/java/android/service/voice/HotwordTrainingAudio.aidl
similarity index 71%
rename from tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
rename to core/java/android/service/voice/HotwordTrainingAudio.aidl
index fe91260..4dd2289 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
+++ b/core/java/android/service/voice/HotwordTrainingAudio.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.apkverity.feature_x;
+package android.service.voice;
 
-import android.app.Activity;
-
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+parcelable HotwordTrainingAudio;
\ No newline at end of file
diff --git a/core/java/android/service/voice/HotwordTrainingAudio.java b/core/java/android/service/voice/HotwordTrainingAudio.java
new file mode 100644
index 0000000..895b0c0
--- /dev/null
+++ b/core/java/android/service/voice/HotwordTrainingAudio.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.voice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.media.AudioFormat;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents audio supporting hotword model training.
+ *
+ * @hide
+ */
+@DataClass(
+        genConstructor = false,
+        genBuilder = true,
+        genEqualsHashCode = true,
+        genHiddenConstDefs = true,
+        genParcelable = true,
+        genToString = true
+)
+@SystemApi
+public final class HotwordTrainingAudio implements Parcelable {
+    /** Represents unset value for the hotword offset. */
+    public static final int HOTWORD_OFFSET_UNSET = -1;
+
+    /** Buffer of hotword audio data for training models. */
+    @NonNull
+    private final byte[] mHotwordAudio;
+
+    private String hotwordAudioToString() {
+        return "length=" + mHotwordAudio.length;
+    }
+
+    /**
+     * The {@link AudioFormat} of the {@link HotwordTrainingAudio#mHotwordAudio}.
+     */
+    @NonNull
+    private final AudioFormat mAudioFormat;
+
+    /**
+     * App-defined identifier to distinguish hotword training audio instances.
+     */
+    @NonNull
+    private final int mAudioType;
+
+    private static int defaultAudioType() {
+        return 0;
+    }
+
+    /**
+     * App-defined offset in milliseconds relative to start of
+     * {@link HotwordTrainingAudio#mHotwordAudio}. Default value is
+     * {@link HotwordTrainingAudio#HOTWORD_OFFSET_UNSET}.
+     */
+    private int mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/voice/HotwordTrainingAudio.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    @DataClass.Generated.Member
+    /* package-private */ HotwordTrainingAudio(
+            @NonNull byte[] hotwordAudio,
+            @NonNull AudioFormat audioFormat,
+            @NonNull int audioType,
+            int hotwordOffsetMillis) {
+        this.mHotwordAudio = hotwordAudio;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHotwordAudio);
+        this.mAudioFormat = audioFormat;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAudioFormat);
+        this.mAudioType = audioType;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAudioType);
+        this.mHotwordOffsetMillis = hotwordOffsetMillis;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Buffer of hotword audio data for training models.
+     */
+    @DataClass.Generated.Member
+    public @NonNull byte[] getHotwordAudio() {
+        return mHotwordAudio;
+    }
+
+    /**
+     * The {@link AudioFormat} of the {@link HotwordTrainingAudio#mHotwordAudio}.
+     */
+    @DataClass.Generated.Member
+    public @NonNull AudioFormat getAudioFormat() {
+        return mAudioFormat;
+    }
+
+    /**
+     * App-defined identifier to distinguish hotword training audio instances.
+     */
+    @DataClass.Generated.Member
+    public @NonNull int getAudioType() {
+        return mAudioType;
+    }
+
+    /**
+     * App-defined offset in milliseconds relative to start of
+     * {@link HotwordTrainingAudio#mHotwordAudio}. Default value is
+     * {@link HotwordTrainingAudio#HOTWORD_OFFSET_UNSET}.
+     */
+    @DataClass.Generated.Member
+    public int getHotwordOffsetMillis() {
+        return mHotwordOffsetMillis;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "HotwordTrainingAudio { " +
+                "hotwordAudio = " + hotwordAudioToString() + ", " +
+                "audioFormat = " + mAudioFormat + ", " +
+                "audioType = " + mAudioType + ", " +
+                "hotwordOffsetMillis = " + mHotwordOffsetMillis +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(HotwordTrainingAudio other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        HotwordTrainingAudio that = (HotwordTrainingAudio) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Arrays.equals(mHotwordAudio, that.mHotwordAudio)
+                && java.util.Objects.equals(mAudioFormat, that.mAudioFormat)
+                && mAudioType == that.mAudioType
+                && mHotwordOffsetMillis == that.mHotwordOffsetMillis;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Arrays.hashCode(mHotwordAudio);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mAudioFormat);
+        _hash = 31 * _hash + mAudioType;
+        _hash = 31 * _hash + mHotwordOffsetMillis;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeByteArray(mHotwordAudio);
+        dest.writeTypedObject(mAudioFormat, flags);
+        dest.writeInt(mAudioType);
+        dest.writeInt(mHotwordOffsetMillis);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ HotwordTrainingAudio(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        byte[] hotwordAudio = in.createByteArray();
+        AudioFormat audioFormat = (AudioFormat) in.readTypedObject(AudioFormat.CREATOR);
+        int audioType = in.readInt();
+        int hotwordOffsetMillis = in.readInt();
+
+        this.mHotwordAudio = hotwordAudio;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHotwordAudio);
+        this.mAudioFormat = audioFormat;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAudioFormat);
+        this.mAudioType = audioType;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAudioType);
+        this.mHotwordOffsetMillis = hotwordOffsetMillis;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<HotwordTrainingAudio> CREATOR
+            = new Parcelable.Creator<HotwordTrainingAudio>() {
+        @Override
+        public HotwordTrainingAudio[] newArray(int size) {
+            return new HotwordTrainingAudio[size];
+        }
+
+        @Override
+        public HotwordTrainingAudio createFromParcel(@NonNull Parcel in) {
+            return new HotwordTrainingAudio(in);
+        }
+    };
+
+    /**
+     * A builder for {@link HotwordTrainingAudio}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @NonNull byte[] mHotwordAudio;
+        private @NonNull AudioFormat mAudioFormat;
+        private @NonNull int mAudioType;
+        private int mHotwordOffsetMillis;
+
+        private long mBuilderFieldsSet = 0L;
+
+        /**
+         * Creates a new Builder.
+         *
+         * @param hotwordAudio
+         *   Buffer of hotword audio data for training models.
+         * @param audioFormat
+         *   The {@link AudioFormat} of the {@link HotwordTrainingAudio#mHotwordAudio}.
+         */
+        public Builder(
+                @NonNull byte[] hotwordAudio,
+                @NonNull AudioFormat audioFormat) {
+            mHotwordAudio = hotwordAudio;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mHotwordAudio);
+            mAudioFormat = audioFormat;
+            com.android.internal.util.AnnotationValidations.validate(
+                    NonNull.class, null, mAudioFormat);
+        }
+
+        /**
+         * Buffer of hotword audio data for training models.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setHotwordAudio(@NonNull byte... value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mHotwordAudio = value;
+            return this;
+        }
+
+        /**
+         * The {@link AudioFormat} of the {@link HotwordTrainingAudio#mHotwordAudio}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setAudioFormat(@NonNull AudioFormat value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mAudioFormat = value;
+            return this;
+        }
+
+        /**
+         * App-defined identifier to distinguish hotword training audio instances.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setAudioType(@NonNull int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4;
+            mAudioType = value;
+            return this;
+        }
+
+        /**
+         * App-defined offset in milliseconds relative to start of
+         * {@link HotwordTrainingAudio#mHotwordAudio}. Default value is
+         * {@link HotwordTrainingAudio#HOTWORD_OFFSET_UNSET}.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setHotwordOffsetMillis(int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x8;
+            mHotwordOffsetMillis = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull HotwordTrainingAudio build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x10; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x4) == 0) {
+                mAudioType = defaultAudioType();
+            }
+            if ((mBuilderFieldsSet & 0x8) == 0) {
+                mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
+            }
+            HotwordTrainingAudio o = new HotwordTrainingAudio(
+                    mHotwordAudio,
+                    mAudioFormat,
+                    mAudioType,
+                    mHotwordOffsetMillis);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x10) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1692837160437L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/service/voice/HotwordTrainingAudio.java",
+            inputSignatures = "public static final  int HOTWORD_OFFSET_UNSET\nprivate final @android.annotation.NonNull byte[] mHotwordAudio\nprivate final @android.annotation.NonNull android.media.AudioFormat mAudioFormat\nprivate final @android.annotation.NonNull int mAudioType\nprivate  int mHotwordOffsetMillis\nprivate  java.lang.String hotwordAudioToString()\nprivate static  int defaultAudioType()\nclass HotwordTrainingAudio extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java b/core/java/android/service/voice/HotwordTrainingData.aidl
similarity index 71%
copy from tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
copy to core/java/android/service/voice/HotwordTrainingData.aidl
index fe91260..03cc841 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
+++ b/core/java/android/service/voice/HotwordTrainingData.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.apkverity.feature_x;
+package android.service.voice;
 
-import android.app.Activity;
-
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+parcelable HotwordTrainingData;
diff --git a/core/java/android/service/voice/HotwordTrainingData.java b/core/java/android/service/voice/HotwordTrainingData.java
new file mode 100644
index 0000000..9dca77e
--- /dev/null
+++ b/core/java/android/service/voice/HotwordTrainingData.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.voice;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Contains training data related to hotword detection service.
+ *
+ * <p>The constructed object's size must be within
+ * {@link HotwordTrainingData#getMaxTrainingDataSize()} or an
+ * {@link IllegalArgumentException} will be thrown on construction. Size of the object is calculated
+ * by converting object to a {@link Parcel} and using the {@link Parcel#dataSize()}.
+ *
+ * @hide
+ */
+@DataClass(
+        genConstructor = false,
+        genBuilder = true,
+        genEqualsHashCode = true,
+        genHiddenConstDefs = true,
+        genParcelable = true,
+        genToString = true)
+@SystemApi
+public final class HotwordTrainingData implements Parcelable {
+    /** Max size for hotword training data. */
+    public static int getMaxTrainingDataSize() {
+        return 1024 * 1024; // 1 MB;
+    }
+
+    /** The list containing hotword audio that is useful for training. */
+    @NonNull
+    @DataClass.PluralOf("trainingAudio")
+    private final List<HotwordTrainingAudio> mTrainingAudios;
+
+    private static List<HotwordTrainingAudio> defaultTrainingAudios() {
+        return Collections.emptyList();
+    }
+
+    /** Timeout stage is unknown. */
+    public static final int TIMEOUT_STAGE_UNKNOWN = 0;
+
+    /**
+     * Timeout stage value that represents that the model timed out very early while detecting
+     * hotword.
+     */
+    public static final int TIMEOUT_STAGE_VERY_EARLY = 1;
+
+    /**
+     * Timeout stage value that represents that the model timed out early while detecting
+     * hotword.
+     */
+    public static final int TIMEOUT_STAGE_EARLY = 2;
+
+    /**
+     * Timeout stage value that represents that the model timed out in the middle while detecting
+     * hotword.
+     */
+    public static final int TIMEOUT_STAGE_MIDDLE = 3;
+
+    /**
+     * Timeout stage value that represents that the model timed out late while detecting
+     * hotword.
+     */
+    public static final int TIMEOUT_STAGE_LATE = 4;
+
+    /** @hide */
+    @IntDef(prefix = {"TIMEOUT_STAGE"}, value = {
+            TIMEOUT_STAGE_UNKNOWN,
+            TIMEOUT_STAGE_VERY_EARLY,
+            TIMEOUT_STAGE_EARLY,
+            TIMEOUT_STAGE_MIDDLE,
+            TIMEOUT_STAGE_LATE,
+    })
+    @interface HotwordTimeoutStage {}
+
+    /** Stage when timeout occurred. */
+    @HotwordTimeoutStage
+    private final int mTimeoutStage;
+
+    private static int defaultTimeoutStage() {
+        return TIMEOUT_STAGE_UNKNOWN;
+    }
+
+    private void onConstructed() {
+        // Verify size of object is within limit.
+        Parcel parcel = Parcel.obtain();
+        parcel.writeValue(this);
+        int dataSizeBytes = parcel.dataSize();
+        parcel.recycle();
+        Preconditions.checkArgument(
+                dataSizeBytes < getMaxTrainingDataSize(),
+                TextUtils.formatSimple(
+                        "Hotword training data of size %s exceeds size limit of %s!",
+                        dataSizeBytes, getMaxTrainingDataSize()));
+    }
+
+
+
+    // Code below generated by codegen v1.0.23.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/voice/HotwordTrainingData.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /** @hide */
+    @IntDef(prefix = "TIMEOUT_STAGE_", value = {
+        TIMEOUT_STAGE_UNKNOWN,
+        TIMEOUT_STAGE_VERY_EARLY,
+        TIMEOUT_STAGE_EARLY,
+        TIMEOUT_STAGE_MIDDLE,
+        TIMEOUT_STAGE_LATE
+    })
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @DataClass.Generated.Member
+    public @interface TimeoutStage {}
+
+    /** @hide */
+    @DataClass.Generated.Member
+    public static String timeoutStageToString(@TimeoutStage int value) {
+        switch (value) {
+            case TIMEOUT_STAGE_UNKNOWN:
+                    return "TIMEOUT_STAGE_UNKNOWN";
+            case TIMEOUT_STAGE_VERY_EARLY:
+                    return "TIMEOUT_STAGE_VERY_EARLY";
+            case TIMEOUT_STAGE_EARLY:
+                    return "TIMEOUT_STAGE_EARLY";
+            case TIMEOUT_STAGE_MIDDLE:
+                    return "TIMEOUT_STAGE_MIDDLE";
+            case TIMEOUT_STAGE_LATE:
+                    return "TIMEOUT_STAGE_LATE";
+            default: return Integer.toHexString(value);
+        }
+    }
+
+    @DataClass.Generated.Member
+    /* package-private */ HotwordTrainingData(
+            @NonNull List<HotwordTrainingAudio> trainingAudios,
+            @HotwordTimeoutStage int timeoutStage) {
+        this.mTrainingAudios = trainingAudios;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTrainingAudios);
+        this.mTimeoutStage = timeoutStage;
+        com.android.internal.util.AnnotationValidations.validate(
+                HotwordTimeoutStage.class, null, mTimeoutStage);
+
+        onConstructed();
+    }
+
+    /**
+     * The list containing hotword audio that is useful for training.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<HotwordTrainingAudio> getTrainingAudios() {
+        return mTrainingAudios;
+    }
+
+    /**
+     * Stage when timeout occurred.
+     */
+    @DataClass.Generated.Member
+    public @HotwordTimeoutStage int getTimeoutStage() {
+        return mTimeoutStage;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "HotwordTrainingData { " +
+                "trainingAudios = " + mTrainingAudios + ", " +
+                "timeoutStage = " + mTimeoutStage +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(HotwordTrainingData other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        HotwordTrainingData that = (HotwordTrainingData) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mTrainingAudios, that.mTrainingAudios)
+                && mTimeoutStage == that.mTimeoutStage;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mTrainingAudios);
+        _hash = 31 * _hash + mTimeoutStage;
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeParcelableList(mTrainingAudios, flags);
+        dest.writeInt(mTimeoutStage);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ HotwordTrainingData(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        List<HotwordTrainingAudio> trainingAudios = new ArrayList<>();
+        in.readParcelableList(trainingAudios, HotwordTrainingAudio.class.getClassLoader());
+        int timeoutStage = in.readInt();
+
+        this.mTrainingAudios = trainingAudios;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mTrainingAudios);
+        this.mTimeoutStage = timeoutStage;
+        com.android.internal.util.AnnotationValidations.validate(
+                HotwordTimeoutStage.class, null, mTimeoutStage);
+
+        onConstructed();
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<HotwordTrainingData> CREATOR
+            = new Parcelable.Creator<HotwordTrainingData>() {
+        @Override
+        public HotwordTrainingData[] newArray(int size) {
+            return new HotwordTrainingData[size];
+        }
+
+        @Override
+        public HotwordTrainingData createFromParcel(@NonNull Parcel in) {
+            return new HotwordTrainingData(in);
+        }
+    };
+
+    /**
+     * A builder for {@link HotwordTrainingData}
+     */
+    @SuppressWarnings("WeakerAccess")
+    @DataClass.Generated.Member
+    public static final class Builder {
+
+        private @NonNull List<HotwordTrainingAudio> mTrainingAudios;
+        private @HotwordTimeoutStage int mTimeoutStage;
+
+        private long mBuilderFieldsSet = 0L;
+
+        public Builder() {
+        }
+
+        /**
+         * The list containing hotword audio that is useful for training.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setTrainingAudios(@NonNull List<HotwordTrainingAudio> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x1;
+            mTrainingAudios = value;
+            return this;
+        }
+
+        /** @see #setTrainingAudios */
+        @DataClass.Generated.Member
+        public @NonNull Builder addTrainingAudio(@NonNull HotwordTrainingAudio value) {
+            if (mTrainingAudios == null) setTrainingAudios(new ArrayList<>());
+            mTrainingAudios.add(value);
+            return this;
+        }
+
+        /**
+         * Stage when timeout occurred.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setTimeoutStage(@HotwordTimeoutStage int value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x2;
+            mTimeoutStage = value;
+            return this;
+        }
+
+        /** Builds the instance. This builder should not be touched after calling this! */
+        public @NonNull HotwordTrainingData build() {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x4; // Mark builder used
+
+            if ((mBuilderFieldsSet & 0x1) == 0) {
+                mTrainingAudios = defaultTrainingAudios();
+            }
+            if ((mBuilderFieldsSet & 0x2) == 0) {
+                mTimeoutStage = defaultTimeoutStage();
+            }
+            HotwordTrainingData o = new HotwordTrainingData(
+                    mTrainingAudios,
+                    mTimeoutStage);
+            return o;
+        }
+
+        private void checkNotUsed() {
+            if ((mBuilderFieldsSet & 0x4) != 0) {
+                throw new IllegalStateException(
+                        "This Builder should not be reused. Use a new Builder instance instead");
+            }
+        }
+    }
+
+    @DataClass.Generated(
+            time = 1693313864628L,
+            codegenVersion = "1.0.23",
+            sourceFile = "frameworks/base/core/java/android/service/voice/HotwordTrainingData.java",
+            inputSignatures = "private final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"trainingAudio\") java.util.List<android.service.voice.HotwordTrainingAudio> mTrainingAudios\npublic static final  int TIMEOUT_STAGE_UNKNOWN\npublic static final  int TIMEOUT_STAGE_VERY_EARLY\npublic static final  int TIMEOUT_STAGE_EARLY\npublic static final  int TIMEOUT_STAGE_MIDDLE\npublic static final  int TIMEOUT_STAGE_LATE\nprivate final @android.service.voice.HotwordTrainingData.HotwordTimeoutStage int mTimeoutStage\npublic static  int getMaxTrainingDataSize()\nprivate static  java.util.List<android.service.voice.HotwordTrainingAudio> defaultTrainingAudios()\nprivate static  int defaultTimeoutStage()\nprivate  void onConstructed()\nclass HotwordTrainingData extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c7e5453..637770c 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1307,9 +1307,9 @@
                     visibleFrame.intersect(mInsetsState.getDisplayFrame());
                     WindowInsets windowInsets = mInsetsState.calculateInsets(visibleFrame,
                             null /* ignoringVisibilityState */, config.isScreenRound(),
-                            false /* alwaysConsumeSystemBars */, mLayout.softInputMode,
-                            mLayout.flags, SYSTEM_UI_FLAG_VISIBLE, mLayout.type,
-                            config.windowConfiguration.getWindowingMode(), null /* idSideMap */);
+                            mLayout.softInputMode, mLayout.flags, SYSTEM_UI_FLAG_VISIBLE,
+                            mLayout.type, config.windowConfiguration.getActivityType(),
+                            null /* idSideMap */);
 
                     if (!fixedSize) {
                         final Rect padding = mIWallpaperEngine.mDisplayPadding;
diff --git a/core/java/android/text/flags/deprecate_fonts_xml.aconfig b/core/java/android/text/flags/deprecate_fonts_xml.aconfig
new file mode 100644
index 0000000..58dc210
--- /dev/null
+++ b/core/java/android/text/flags/deprecate_fonts_xml.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.text.flags"
+
+flag {
+  name: "deprecate_fonts_xml"
+  namespace: "text"
+  description: "Feature flag for deprecating fonts.xml. By setting true for this feature flag, the new font configuration XML, /system/etc/font_fallback.xml is used. The new XML has a new syntax and flexibility of variable font declarations, but it is not compatible with the apps that reads fonts.xml. So, fonts.xml is maintained as a subset of the font_fallback.xml"
+  bug: "281769620"
+}
diff --git a/core/java/android/text/flags/phrase_strict_fallback.aconfig b/core/java/android/text/flags/phrase_strict_fallback.aconfig
new file mode 100644
index 0000000..c67a21b
--- /dev/null
+++ b/core/java/android/text/flags/phrase_strict_fallback.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.text.flags"
+
+flag {
+  name: "phrase_strict_fallback"
+  namespace: "text"
+  description: "Feature flag for automatic fallback from phrase based line break to strict line break."
+  bug: "281970875"
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 85f5395..12527e9 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -156,6 +156,13 @@
     public static final String SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS =
             "settings_biometrics2_fingerprint";
 
+    /**
+     * Flag to enable/disable remote auth enrollment and settings
+     * @hide
+     */
+    public static final String SETTINGS_REMOTEAUTH_ENROLLMENT_SETTINGS =
+            "settings_remoteauth_enrollment";
+
     /** Flag to enable/disable entire page in Accessibility -> Hearing aids
      *  @hide
      */
@@ -247,7 +254,8 @@
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true");
         DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true");
         DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS, "false");
-        DEFAULT_FLAGS.put("settings_press_hold_nav_handle_to_search", "false");
+        // TODO: b/298454866 Replace with Trunk Stable Feature Flag
+        DEFAULT_FLAGS.put(SETTINGS_REMOTEAUTH_ENROLLMENT_SETTINGS, "false");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 23afb03..a208d1f 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -81,6 +81,8 @@
     private int mConnectionCount = 0;
     private final InputMethodManager mImm;
 
+    private final Rect mTempRect = new Rect();
+
     private final RectF mTempRectF = new RectF();
 
     private final Region mTempRegion = new Region();
@@ -401,8 +403,9 @@
 
             final View cachedHoverTarget = getCachedHoverTarget();
             if (cachedHoverTarget != null) {
-                final Rect handwritingArea = getViewHandwritingArea(cachedHoverTarget);
-                if (isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget,
+                final Rect handwritingArea = mTempRect;
+                if (getViewHandwritingArea(cachedHoverTarget, handwritingArea)
+                        && isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget,
                         /* isHover */ true)
                         && shouldTriggerStylusHandwritingForView(cachedHoverTarget)) {
                     return cachedHoverTarget;
@@ -445,8 +448,9 @@
         // directly return the connectedView.
         final View connectedView = getConnectedView();
         if (connectedView != null) {
-            Rect handwritingArea = getViewHandwritingArea(connectedView);
-            if (isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
+            Rect handwritingArea = mTempRect;
+            if (getViewHandwritingArea(connectedView, handwritingArea)
+                    && isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
                     && shouldTriggerStylusHandwritingForView(connectedView)) {
                 return connectedView;
             }
@@ -528,28 +532,30 @@
     /**
      * Return the handwriting area of the given view, represented in the window's coordinate.
      * If the view didn't set any handwriting area, it will return the view's boundary.
-     * It will return null if the view or its handwriting area is not visible.
      *
-     * The handwriting area is clipped to its visible part.
+     * <p> The handwriting area is clipped to its visible part.
      * Notice that the returned rectangle is the view's original handwriting area without the
-     * view's handwriting area extends.
+     * view's handwriting area extends. </p>
+     *
+     * @param view the {@link View} whose handwriting area we want to compute.
+     * @param rect the {@link Rect} to receive the result.
+     *
+     * @return true if the view's handwriting area is still visible, or false if it's clipped and
+     * fully invisible. This method only consider the clip by given view's parents, but not the case
+     * where a view is covered by its sibling view.
      */
-    @Nullable
-    private static Rect getViewHandwritingArea(@NonNull View view) {
+    private static boolean getViewHandwritingArea(@NonNull View view, @NonNull Rect rect) {
         final ViewParent viewParent = view.getParent();
         if (viewParent != null && view.isAttachedToWindow() && view.isAggregatedVisible()) {
             final Rect localHandwritingArea = view.getHandwritingArea();
-            final Rect globalHandwritingArea = new Rect();
             if (localHandwritingArea != null) {
-                globalHandwritingArea.set(localHandwritingArea);
+                rect.set(localHandwritingArea);
             } else {
-                globalHandwritingArea.set(0, 0, view.getWidth(), view.getHeight());
+                rect.set(0, 0, view.getWidth(), view.getHeight());
             }
-            if (viewParent.getChildVisibleRect(view, globalHandwritingArea, null)) {
-                return globalHandwritingArea;
-            }
+            return viewParent.getChildVisibleRect(view, rect, null);
         }
-        return null;
+        return false;
     }
 
     /**
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index fabfed3..1ec7c41 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.EventLogTags.IMF_IME_ANIM_CANCEL;
 import static android.view.EventLogTags.IMF_IME_ANIM_FINISH;
 import static android.view.EventLogTags.IMF_IME_ANIM_START;
@@ -39,6 +39,7 @@
 import static android.view.InsetsState.ISIDE_RIGHT;
 import static android.view.InsetsState.ISIDE_TOP;
 import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
 import static android.view.inputmethod.ImeTracker.TOKEN_NONE;
@@ -62,7 +63,6 @@
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsAnimation.Bounds;
-import android.view.WindowManager.LayoutParams;
 import android.view.animation.Interpolator;
 import android.view.inputmethod.ImeTracker;
 
@@ -396,10 +396,9 @@
     private Insets getInsetsFromState(InsetsState state, Rect frame,
             @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
         return state.calculateInsets(frame, null /* ignoringVisibilityState */,
-                false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
-                LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/,
+                false /* isScreenRound */, SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode */,
                 0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, idSideMap).getInsets(mTypes);
+                ACTIVITY_TYPE_UNDEFINED, idSideMap).getInsets(mTypes);
     }
 
     /** Computes the insets relative to the given frame. */
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8ec7d67..fb24211 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -652,7 +652,7 @@
     private int mLastLegacySoftInputMode;
     private int mLastLegacyWindowFlags;
     private int mLastLegacySystemUiFlags;
-    private int mLastWindowingMode;
+    private int mLastActivityType;
     private boolean mStartingAnimation;
     private int mCaptionInsetsHeight = 0;
     private int mImeCaptionBarInsetsHeight = 0;
@@ -800,10 +800,10 @@
                 }
             }
 
-            WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
-                    mLastInsets.isRound(), false /* alwaysConsumeSystemBars */,
+            WindowInsets insets = state.calculateInsets(mFrame,
+                    mState /* ignoringVisibilityState */, mLastInsets.isRound(),
                     mLastLegacySoftInputMode, mLastLegacyWindowFlags, mLastLegacySystemUiFlags,
-                    mWindowType, mLastWindowingMode, null /* idSideMap */);
+                    mWindowType, mLastActivityType, null /* idSideMap */);
             mHost.dispatchWindowInsetsAnimationProgress(insets,
                     Collections.unmodifiableList(runningAnimations));
             if (DEBUG) {
@@ -939,30 +939,29 @@
     }
 
     /**
-     * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, boolean, int, int, int, int,
-     *      int, android.util.SparseIntArray)
+     * @see InsetsState#calculateInsets(Rect, InsetsState, boolean, int, int, int, int, int,
+     *      android.util.SparseIntArray)
      */
     @VisibleForTesting
-    public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars,
-            int windowType, int windowingMode, int legacySoftInputMode, int legacyWindowFlags,
-            int legacySystemUiFlags) {
+    public WindowInsets calculateInsets(boolean isScreenRound, int windowType, int activityType,
+            int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) {
         mWindowType = windowType;
-        mLastWindowingMode = windowingMode;
+        mLastActivityType = activityType;
         mLastLegacySoftInputMode = legacySoftInputMode;
         mLastLegacyWindowFlags = legacyWindowFlags;
         mLastLegacySystemUiFlags = legacySystemUiFlags;
-        mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
-                isScreenRound, alwaysConsumeSystemBars, legacySoftInputMode, legacyWindowFlags,
-                legacySystemUiFlags, windowType, windowingMode, null /* idSideMap */);
+        mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState */,
+                isScreenRound, legacySoftInputMode, legacyWindowFlags,
+                legacySystemUiFlags, windowType, activityType, null /* idSideMap */);
         return mLastInsets;
     }
 
     /**
      * @see InsetsState#calculateVisibleInsets(Rect, int, int, int, int)
      */
-    public Insets calculateVisibleInsets(int windowType, int windowingMode,
+    public Insets calculateVisibleInsets(int windowType, int activityType,
             @SoftInputModeFlags int softInputMode, int windowFlags) {
-        return mState.calculateVisibleInsets(mFrame, windowType, windowingMode, softInputMode,
+        return mState.calculateVisibleInsets(mFrame, windowType, activityType, softInputMode,
                 windowFlags);
     }
 
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index af24140..59e0932 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
 import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
 import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
@@ -39,7 +40,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.WindowConfiguration;
+import android.app.WindowConfiguration.ActivityType;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Parcel;
@@ -136,9 +137,8 @@
      * @return The calculated insets.
      */
     public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState,
-            boolean isScreenRound, boolean alwaysConsumeSystemBars,
-            int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
-            int windowType, @WindowConfiguration.WindowingMode int windowingMode,
+            boolean isScreenRound, int legacySoftInputMode, int legacyWindowFlags,
+            int legacySystemUiFlags, int windowType, @ActivityType int activityType,
             @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
         Insets[] typeInsetsMap = new Insets[Type.SIZE];
         Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
@@ -185,9 +185,8 @@
         if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
             compatInsetsTypes &= ~statusBars();
         }
-        if (clearsCompatInsets(windowType, legacyWindowFlags, windowingMode)) {
-            // Clear all types but forceConsumingTypes.
-            compatInsetsTypes &= forceConsumingTypes;
+        if (clearsCompatInsets(windowType, legacyWindowFlags, activityType, forceConsumingTypes)) {
+            compatInsetsTypes = 0;
         }
 
         return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
@@ -295,26 +294,27 @@
         return insets;
     }
 
-    public Insets calculateVisibleInsets(Rect frame, int windowType, int windowingMode,
+    public Insets calculateVisibleInsets(Rect frame, int windowType, @ActivityType int activityType,
             @SoftInputModeFlags int softInputMode, int windowFlags) {
-        final boolean clearsCompatInsets = clearsCompatInsets(
-                windowType, windowFlags, windowingMode);
         final int softInputAdjustMode = softInputMode & SOFT_INPUT_MASK_ADJUST;
         final int visibleInsetsTypes = softInputAdjustMode != SOFT_INPUT_ADJUST_NOTHING
                 ? systemBars() | ime()
                 : systemBars();
+        @InsetsType int forceConsumingTypes = 0;
         Insets insets = Insets.NONE;
         for (int i = mSources.size() - 1; i >= 0; i--) {
             final InsetsSource source = mSources.valueAt(i);
             if ((source.getType() & visibleInsetsTypes) == 0) {
                 continue;
             }
-            if (clearsCompatInsets && !source.hasFlags(FLAG_FORCE_CONSUMING)) {
-                continue;
+            if (source.hasFlags(FLAG_FORCE_CONSUMING)) {
+                forceConsumingTypes |= source.getType();
             }
             insets = Insets.max(source.calculateVisibleInsets(frame), insets);
         }
-        return insets;
+        return clearsCompatInsets(windowType, windowFlags, activityType, forceConsumingTypes)
+                ? Insets.NONE
+                : insets;
     }
 
     /**
@@ -662,10 +662,15 @@
         mSources.put(source.getId(), source);
     }
 
-    public static boolean clearsCompatInsets(int windowType, int windowFlags, int windowingMode) {
+    public static boolean clearsCompatInsets(int windowType, int windowFlags,
+            @ActivityType int activityType, @InsetsType int forceConsumingTypes) {
         return (windowFlags & FLAG_LAYOUT_NO_LIMITS) != 0
+                // For compatibility reasons, this excludes the wallpaper, the system error windows,
+                // and the app windows while any system bar is forcibly consumed.
                 && windowType != TYPE_WALLPAPER && windowType != TYPE_SYSTEM_ERROR
-                && !WindowConfiguration.inMultiWindowMode(windowingMode);
+                // This ensures the app content won't be obscured by compat insets even if the app
+                // has FLAG_LAYOUT_NO_LIMITS.
+                && (forceConsumingTypes == 0 || activityType != ACTIVITY_TYPE_STANDARD);
     }
 
     public void dump(String prefix, PrintWriter pw) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9a4cb72..81edd3c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -105,6 +105,8 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.os.Vibrator;
+import android.os.vibrator.Flags;
 import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
@@ -2447,7 +2449,6 @@
      * @see #getId()
      */
     @IdRes
-    @ViewDebug.ExportedProperty(resolveId = true)
     int mID = NO_ID;
 
     /** The ID of this view for autofill purposes.
@@ -4298,71 +4299,6 @@
      * This view's request for the visibility of the status bar.
      * @hide
      */
-    @ViewDebug.ExportedProperty(flagMapping = {
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE,
-                    equals = SYSTEM_UI_FLAG_LOW_PROFILE,
-                    name = "LOW_PROFILE"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION,
-                    equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION,
-                    name = "HIDE_NAVIGATION"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN,
-                    equals = SYSTEM_UI_FLAG_FULLSCREEN,
-                    name = "FULLSCREEN"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE,
-                    equals = SYSTEM_UI_FLAG_LAYOUT_STABLE,
-                    name = "LAYOUT_STABLE"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
-                    equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
-                    name = "LAYOUT_HIDE_NAVIGATION"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
-                    equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
-                    name = "LAYOUT_FULLSCREEN"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE,
-                    equals = SYSTEM_UI_FLAG_IMMERSIVE,
-                    name = "IMMERSIVE"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
-                    equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
-                    name = "IMMERSIVE_STICKY"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
-                    equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
-                    name = "LIGHT_STATUS_BAR"),
-            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
-                    equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
-                    name = "LIGHT_NAVIGATION_BAR"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND,
-                    equals = STATUS_BAR_DISABLE_EXPAND,
-                    name = "STATUS_BAR_DISABLE_EXPAND"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
-                    equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
-                    name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
-                    equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
-                    name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
-                    equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
-                    name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO,
-                    equals = STATUS_BAR_DISABLE_SYSTEM_INFO,
-                    name = "STATUS_BAR_DISABLE_SYSTEM_INFO"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME,
-                    equals = STATUS_BAR_DISABLE_HOME,
-                    name = "STATUS_BAR_DISABLE_HOME"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK,
-                    equals = STATUS_BAR_DISABLE_BACK,
-                    name = "STATUS_BAR_DISABLE_BACK"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK,
-                    equals = STATUS_BAR_DISABLE_CLOCK,
-                    name = "STATUS_BAR_DISABLE_CLOCK"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT,
-                    equals = STATUS_BAR_DISABLE_RECENT,
-                    name = "STATUS_BAR_DISABLE_RECENT"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH,
-                    equals = STATUS_BAR_DISABLE_SEARCH,
-                    name = "STATUS_BAR_DISABLE_SEARCH"),
-            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
-                    equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
-                    name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP")
-    }, formatToHexString = true)
     @SystemUiVisibility
     int mSystemUiVisibility;
 
@@ -4481,7 +4417,6 @@
      * to the left edge of this view.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "layout")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mLeft;
     /**
@@ -4489,7 +4424,6 @@
      * to the right edge of this view.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "layout")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mRight;
     /**
@@ -4497,7 +4431,6 @@
      * to the top edge of this view.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "layout")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mTop;
     /**
@@ -4505,7 +4438,6 @@
      * to the bottom edge of this view.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "layout")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mBottom;
 
@@ -4516,7 +4448,6 @@
      * accessing these directly.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "scrolling")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mScrollX;
     /**
@@ -4526,7 +4457,6 @@
      * accessing these directly.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "scrolling")
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mScrollY;
 
@@ -4535,7 +4465,6 @@
      * pixels between the left edge of this view and the left edge of its content.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingLeft = 0;
     /**
@@ -4543,7 +4472,6 @@
      * pixels between the right edge of this view and the right edge of its content.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingRight = 0;
     /**
@@ -4551,7 +4479,6 @@
      * pixels between the top edge of this view and the top edge of its content.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingTop;
     /**
@@ -4559,7 +4486,6 @@
      * pixels between the bottom edge of this view and the bottom edge of its content.
      * {@hide}
      */
-    @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingBottom;
 
@@ -5411,6 +5337,9 @@
      */
     private PointerIcon mMousePointerIcon;
 
+    /** Vibrator for haptic feedback. */
+    private Vibrator mVibrator;
+
     /**
      * @hide
      */
@@ -17918,6 +17847,7 @@
      * @return The left edge of the displayed part of your view, in pixels.
      */
     @InspectableProperty
+    @ViewDebug.ExportedProperty(category = "scrolling")
     public final int getScrollX() {
         return mScrollX;
     }
@@ -17930,6 +17860,7 @@
      * @return The top edge of the displayed part of your view, in pixels.
      */
     @InspectableProperty
+    @ViewDebug.ExportedProperty(category = "scrolling")
     public final int getScrollY() {
         return mScrollY;
     }
@@ -18720,6 +18651,7 @@
      * @return The top of this view, in pixels.
      */
     @ViewDebug.CapturedViewProperty
+    @ViewDebug.ExportedProperty(category = "layout")
     public final int getTop() {
         return mTop;
     }
@@ -18779,6 +18711,7 @@
      * @return The bottom of this view, in pixels.
      */
     @ViewDebug.CapturedViewProperty
+    @ViewDebug.ExportedProperty(category = "layout")
     public final int getBottom() {
         return mBottom;
     }
@@ -18844,6 +18777,7 @@
      * @return The left edge of this view, in pixels.
      */
     @ViewDebug.CapturedViewProperty
+    @ViewDebug.ExportedProperty(category = "layout")
     public final int getLeft() {
         return mLeft;
     }
@@ -18903,6 +18837,7 @@
      * @return The right edge of this view, in pixels.
      */
     @ViewDebug.CapturedViewProperty
+    @ViewDebug.ExportedProperty(category = "layout")
     public final int getRight() {
         return mRight;
     }
@@ -26130,6 +26065,7 @@
      * @return the top padding in pixels
      */
     @InspectableProperty
+    @ViewDebug.ExportedProperty(category = "padding")
     public int getPaddingTop() {
         return mPaddingTop;
     }
@@ -26142,6 +26078,7 @@
      * @return the bottom padding in pixels
      */
     @InspectableProperty
+    @ViewDebug.ExportedProperty(category = "padding")
     public int getPaddingBottom() {
         return mPaddingBottom;
     }
@@ -26154,6 +26091,7 @@
      * @return the left padding in pixels
      */
     @InspectableProperty
+    @ViewDebug.ExportedProperty(category = "padding")
     public int getPaddingLeft() {
         if (!isPaddingResolved()) {
             resolvePadding();
@@ -26184,6 +26122,7 @@
      * @return the right padding in pixels
      */
     @InspectableProperty
+    @ViewDebug.ExportedProperty(category = "padding")
     public int getPaddingRight() {
         if (!isPaddingResolved()) {
             resolvePadding();
@@ -26869,6 +26808,7 @@
      */
     @IdRes
     @ViewDebug.CapturedViewProperty
+    @ViewDebug.ExportedProperty(resolveId = true)
     @InspectableProperty
     public int getId() {
         return mID;
@@ -27758,8 +27698,24 @@
                 && !isHapticFeedbackEnabled()) {
             return false;
         }
-        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
-                (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
+
+        final boolean always = (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0;
+        if (Flags.useVibratorHapticFeedback()) {
+            if (!mAttachInfo.canPerformHapticFeedback()) {
+                return false;
+            }
+            getSystemVibrator().performHapticFeedback(
+                    feedbackConstant, always, "View#performHapticFeedback");
+            return true;
+        }
+        return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, always);
+    }
+
+    private Vibrator getSystemVibrator() {
+        if (mVibrator != null) {
+            return mVibrator;
+        }
+        return mVibrator = mContext.getSystemService(Vibrator.class);
     }
 
     /**
@@ -27832,6 +27788,71 @@
      * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController}
      * instead.
      */
+    @ViewDebug.ExportedProperty(flagMapping = {
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE,
+                    equals = SYSTEM_UI_FLAG_LOW_PROFILE,
+                    name = "LOW_PROFILE"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION,
+                    equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION,
+                    name = "HIDE_NAVIGATION"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN,
+                    equals = SYSTEM_UI_FLAG_FULLSCREEN,
+                    name = "FULLSCREEN"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE,
+                    equals = SYSTEM_UI_FLAG_LAYOUT_STABLE,
+                    name = "LAYOUT_STABLE"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
+                    equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
+                    name = "LAYOUT_HIDE_NAVIGATION"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
+                    equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
+                    name = "LAYOUT_FULLSCREEN"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE,
+                    equals = SYSTEM_UI_FLAG_IMMERSIVE,
+                    name = "IMMERSIVE"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
+                    equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
+                    name = "IMMERSIVE_STICKY"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+                    equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+                    name = "LIGHT_STATUS_BAR"),
+            @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                    equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+                    name = "LIGHT_NAVIGATION_BAR"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND,
+                    equals = STATUS_BAR_DISABLE_EXPAND,
+                    name = "STATUS_BAR_DISABLE_EXPAND"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
+                    equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
+                    name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
+                    equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
+                    name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
+                    equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
+                    name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO,
+                    equals = STATUS_BAR_DISABLE_SYSTEM_INFO,
+                    name = "STATUS_BAR_DISABLE_SYSTEM_INFO"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME,
+                    equals = STATUS_BAR_DISABLE_HOME,
+                    name = "STATUS_BAR_DISABLE_HOME"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK,
+                    equals = STATUS_BAR_DISABLE_BACK,
+                    name = "STATUS_BAR_DISABLE_BACK"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK,
+                    equals = STATUS_BAR_DISABLE_CLOCK,
+                    name = "STATUS_BAR_DISABLE_CLOCK"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT,
+                    equals = STATUS_BAR_DISABLE_RECENT,
+                    name = "STATUS_BAR_DISABLE_RECENT"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH,
+                    equals = STATUS_BAR_DISABLE_SEARCH,
+                    name = "STATUS_BAR_DISABLE_SEARCH"),
+            @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
+                    equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP,
+                    name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP")
+    }, formatToHexString = true)
     @Deprecated
     public int getSystemUiVisibility() {
         return mSystemUiVisibility;
@@ -31239,6 +31260,11 @@
             return events;
         }
 
+        private boolean canPerformHapticFeedback() {
+            return mSession != null
+                    && (mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) == 0;
+        }
+
         @Nullable
         ScrollCaptureInternal getScrollCaptureInternal() {
             if (mScrollCaptureInternal != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bfe5cfb..d191ccd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -154,7 +154,6 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.sysprop.DisplayProperties;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
@@ -1734,21 +1733,8 @@
         return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
     }
 
-    /** Returns true if force dark should be enabled according to various settings */
-    @VisibleForTesting
-    public boolean isForceDarkEnabled() {
-        boolean isForceInvertEnabled = Settings.Secure.getIntForUser(
-                mContext.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
-                /* def= */ 0,
-                UserHandle.myUserId()) == 1;
-        // Force invert ignores all developer opt-outs.
-        // We also ignore dark theme, since the app developer can override the user's preference
-        // for dark mode in configuration.uiMode. Instead, we assume that the force invert setting
-        // will be enabled at the same time dark theme is in the Settings app.
-        if (isForceInvertEnabled) {
-            return true;
-        }
+    private void updateForceDarkMode() {
+        if (mAttachInfo.mThreadedRenderer == null) return;
 
         boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
 
@@ -1760,12 +1746,8 @@
                     && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
             a.recycle();
         }
-        return useAutoDark;
-    }
 
-    private void updateForceDarkMode() {
-        if (mAttachInfo.mThreadedRenderer == null) return;
-        if (mAttachInfo.mThreadedRenderer.setForceDark(isForceDarkEnabled())) {
+        if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) {
             // TODO: Don't require regenerating all display lists to apply this setting
             invalidateWorld(mView);
         }
@@ -2866,16 +2848,15 @@
         if (mLastWindowInsets == null || forceConstruct) {
             final Configuration config = getConfiguration();
             mLastWindowInsets = mInsetsController.calculateInsets(
-                    config.isScreenRound(), mAttachInfo.mAlwaysConsumeSystemBars,
-                    mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
-                    mWindowAttributes.softInputMode, mWindowAttributes.flags,
-                    (mWindowAttributes.systemUiVisibility
+                    config.isScreenRound(), mWindowAttributes.type,
+                    config.windowConfiguration.getActivityType(), mWindowAttributes.softInputMode,
+                    mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility
                             | mWindowAttributes.subtreeSystemUiVisibility));
 
             mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
             mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
             mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
-                    mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
+                    mWindowAttributes.type, config.windowConfiguration.getActivityType(),
                     mWindowAttributes.softInputMode, mWindowAttributes.flags).toRect());
         }
         return mLastWindowInsets;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 62e37a4..b8385c6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1318,8 +1318,8 @@
      * that have the ignore orientation request display setting enabled by OEMs
      * (enables compatibility mode for fixed orientation on Android 12 (API
      * level 31) or higher; see
-     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-app-compatibility">
-     * Large screen app compatibility</a>
+     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-compatibility-mode">
+     * Large screen compatibility mode</a>
      * for more details).
      *
      * <p>To opt out of the user aspect ratio compatibility override, add this property
@@ -1358,8 +1358,8 @@
      * that have the ignore orientation request display setting enabled by OEMs
      * (enables compatibility mode for fixed orientation on Android 12 (API
      * level 31) or higher; see
-     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-app-compatibility">
-     * Large screen app compatibility</a>
+     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-compatibility-mode">
+     * Large screen compatibility mode</a>
      * for more details).
      *
      * <p>To opt out of the full-screen option of the user aspect ratio compatibility
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index f67a61b..61470f2 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -28,7 +28,13 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UiThread;
+import android.app.UriGrantsManager;
+import android.content.ContentProvider;
+import android.content.Intent;
 import android.graphics.RectF;
+import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.CancellationSignalBeamer;
@@ -37,6 +43,7 @@
 import android.os.Looper;
 import android.os.ResultReceiver;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
 import android.view.KeyEvent;
@@ -1143,7 +1150,22 @@
     public void commitContent(InputConnectionCommandHeader header,
             InputContentInfo inputContentInfo, int flags, Bundle opts,
             AndroidFuture future /* T=Boolean */) {
+        final int imeUid = Binder.getCallingUid();
         dispatchWithTracing("commitContent", future, () -> {
+            // Check if the originator IME has the right permissions
+            try {
+                final int contentUriOwnerUserId = ContentProvider.getUserIdFromUri(
+                        inputContentInfo.getContentUri(), UserHandle.getUserId(imeUid));
+                final Uri contentUriWithoutUserId = ContentProvider.getUriWithoutUserId(
+                        inputContentInfo.getContentUri());
+                UriGrantsManager.getService().checkGrantUriPermission_ignoreNonSystem(imeUid, null,
+                        contentUriWithoutUserId, Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                        contentUriOwnerUserId);
+            } catch (Exception e) {
+                Log.w(TAG, "commitContent with invalid Uri permission from IME:", e);
+                return false;
+            }
+
             if (header.mSessionId != mCurrentSessionId.get()) {
                 return false;  // cancelled
             }
diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig
new file mode 100644
index 0000000..92d3408
--- /dev/null
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.view.inputmethod"
+
+flag {
+    name: "refactor_insets_controller"
+    namespace: "inputmethod"
+    description: "Feature flag for refactoring InsetsController and removing ImeInsetsSourceConsumer"
+    bug: "298172246"
+}
\ No newline at end of file
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6523fff..f5b81b0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -50,6 +50,7 @@
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
@@ -3139,4 +3140,15 @@
         if (result == null) return super.onApplyWindowInsets(insets);
         return result;
     }
+
+    @Override
+    @Nullable
+    public PointerIcon onResolvePointerIcon(@NonNull MotionEvent event, int pointerIndex) {
+        PointerIcon icon =
+                mProvider.getViewDelegate().onResolvePointerIcon(event, pointerIndex);
+        if (icon != null) {
+            return icon;
+        }
+        return super.onResolvePointerIcon(event, pointerIndex);
+    }
 }
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 26579c5d..ca423e0 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -39,6 +39,7 @@
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.PointerIcon;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowInsets;
@@ -496,6 +497,15 @@
         default WindowInsets onApplyWindowInsets(@Nullable WindowInsets insets) {
             return null;
         }
+
+        /**
+         * @hide Only used by WebView.
+         */
+        @SuppressWarnings("unused")
+        @Nullable
+        default PointerIcon onResolvePointerIcon(@NonNull MotionEvent event, int pointerIndex) {
+            return null;
+        }
     }
 
     interface ScrollDelegate {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f99f138..ddcfb40 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2098,17 +2098,14 @@
         final int selectionEnd = mTextView.getSelectionEnd();
 
         final InputMethodState ims = mInputMethodState;
-        if (ims != null && ims.mBatchEditNesting == 0) {
+        if (ims != null && ims.mBatchEditNesting == 0
+                && (ims.mContentChanged || ims.mSelectionModeChanged)) {
             InputMethodManager imm = getInputMethodManager();
-            if (imm != null) {
-                if (imm.isActive(mTextView)) {
-                    if (ims.mContentChanged || ims.mSelectionModeChanged) {
-                        // We are in extract mode and the content has changed
-                        // in some way... just report complete new text to the
-                        // input method.
-                        reportExtractedText();
-                    }
-                }
+            if (imm != null && imm.hasActiveInputConnection(mTextView)) {
+                // We are in extract mode and the content has changed
+                // in some way... just report complete new text to the
+                // input method.
+                reportExtractedText();
             }
         }
 
@@ -4830,7 +4827,7 @@
             if (null == imm) {
                 return;
             }
-            if (!imm.isActive(mTextView)) {
+            if (!imm.hasActiveInputConnection(mTextView)) {
                 return;
             }
             // Skip if the IME has not requested the cursor/anchor position.
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index da09489..b4d7a94 100755
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -2109,7 +2109,7 @@
                 return;
             }
 
-            if (imm.isActive(this)) {
+            if (imm.hasActiveInputConnection(this)) {
                 // This means that SearchAutoComplete is already connected to the IME.
                 // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check.
                 mHasPendingShowSoftInputRequest = false;
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index c270053..2747233a 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -17,8 +17,10 @@
 package android.window;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.INVALID_DISPLAY;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
@@ -107,18 +109,38 @@
     }
 
     /**
-     * Returns {@code true} if the given activities can be displayed on this virtual display and
-     * the windowing mode is supported.
+     * Returns {@code true} if all of the given activities can be launched on this virtual display
+     * in the configuration defined by the rest of the arguments.
+     *
+     * @see #canContainActivity
      */
-    public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities,
-            @WindowConfiguration.WindowingMode int windowingMode);
+    public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+            @WindowConfiguration.WindowingMode int windowingMode) {
+        for (int i = 0; i < activities.size(); i++) {
+            if (!canContainActivity(activities.get(i), windowingMode,
+                    /*launchingFromDisplayId=*/ INVALID_DISPLAY, /*isNewTask=*/ false)) {
+                return false;
+            }
+        }
+        return true;
+    }
 
     /**
-     * Returns {@code true} if the given new task can be launched on this virtual display.
+     * Returns {@code true} if the given activity can be launched on this virtual display in the
+     * configuration defined by the rest of the arguments. If the given intent would be intercepted
+     * by the display owner then this means that the activity cannot be launched.
      */
-    public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo, Intent intent,
-            @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
-            boolean isNewTask);
+    public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
+            @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
+            int launchingFromDisplayId, boolean isNewTask);
+
+    /**
+     * Returns {@code true} if the given activity can be launched on this virtual display in the
+     * configuration defined by the rest of the arguments.
+     */
+    protected abstract boolean canContainActivity(@NonNull ActivityInfo activityInfo,
+            @WindowConfiguration.WindowingMode int windowingMode,
+            int launchingFromDisplayId, boolean isNewTask);
 
     /**
      * Called when an Activity window is layouted with the new changes where contains the
diff --git a/core/java/android/window/WindowMetricsController.java b/core/java/android/window/WindowMetricsController.java
index 2858f0a..e32c8e5 100644
--- a/core/java/android/window/WindowMetricsController.java
+++ b/core/java/android/window/WindowMetricsController.java
@@ -16,7 +16,7 @@
 
 package android.window;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 
@@ -80,7 +80,7 @@
         final Rect bounds;
         final float density;
         final boolean isScreenRound;
-        final int windowingMode;
+        final int activityType;
         synchronized (ResourcesManager.getInstance()) {
             final Configuration config = mContext.getResources().getConfiguration();
             final WindowConfiguration winConfig = config.windowConfiguration;
@@ -90,11 +90,11 @@
             // as DisplayMetrics#density
             density = config.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
             isScreenRound = config.isScreenRound();
-            windowingMode = winConfig.getWindowingMode();
+            activityType = winConfig.getActivityType();
         }
         final IBinder token = Context.getToken(mContext);
         final Supplier<WindowInsets> insetsSupplier = () -> getWindowInsetsFromServerForDisplay(
-                mContext.getDisplayId(), token, bounds, isScreenRound, windowingMode);
+                mContext.getDisplayId(), token, bounds, isScreenRound, activityType);
         return new WindowMetrics(new Rect(bounds), insetsSupplier, density);
     }
 
@@ -105,23 +105,22 @@
      * @param token the token of Activity or WindowContext
      * @param bounds the window bounds to calculate insets for
      * @param isScreenRound if the display identified by displayId is round
-     * @param windowingMode the windowing mode of the window to calculate insets for
+     * @param activityType the activity type of the window to calculate insets for
      * @return WindowInsets calculated for the given window bounds, on the given display
      */
     private static WindowInsets getWindowInsetsFromServerForDisplay(int displayId, IBinder token,
-            Rect bounds, boolean isScreenRound, int windowingMode) {
+            Rect bounds, boolean isScreenRound, int activityType) {
         try {
             final InsetsState insetsState = new InsetsState();
-            final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
-                    .getWindowInsets(displayId, token, insetsState);
+            WindowManagerGlobal.getWindowManagerService().getWindowInsets(
+                    displayId, token, insetsState);
             final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale();
             if (overrideInvScale != 1f) {
                 insetsState.scale(overrideInvScale);
             }
             return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState */,
-                    isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING,
-                    0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
-                    WindowManager.LayoutParams.INVALID_WINDOW_TYPE, windowingMode,
+                    isScreenRound, SOFT_INPUT_ADJUST_NOTHING, 0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
+                    WindowManager.LayoutParams.INVALID_WINDOW_TYPE, activityType,
                     null /* idSideMap */);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -157,7 +156,7 @@
                     currentDisplayInfo.displayId, null /* token */,
                     new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
                             currentDisplayInfo.getNaturalHeight()), isScreenRound,
-                    WINDOWING_MODE_FULLSCREEN);
+                    ACTIVITY_TYPE_UNDEFINED);
             // Set the hardware-provided insets.
             windowInsets = new WindowInsets.Builder(windowInsets).setRoundedCorners(
                             currentDisplayInfo.roundedCorners)
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 560e41b..b8d251f 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -8,3 +8,10 @@
     description: "Whether the feature to sync different window-related config updates is enabled"
     bug: "260873529"
 }
+
+flag {
+    namespace: "windowing_sdk"
+    name: "activity_embedding_overlay_presentation_flag"
+    description: "Whether the overlay presentation feature is enabled"
+    bug: "243518738"
+}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index fff778c..755113b 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -33,6 +33,7 @@
 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED;
 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
 import static com.android.internal.app.procstats.ProcessStats.STATE_FGS;
+import static com.android.internal.app.procstats.ProcessStats.STATE_FROZEN;
 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
@@ -142,6 +143,7 @@
     private ProcessState mCommonProcess;
     private int mCurCombinedState = STATE_NOTHING;
     private long mStartTime;
+    private int mStateBeforeFrozen = STATE_NOTHING;
 
     private int mLastPssState = STATE_NOTHING;
     private long mLastPssTime;
@@ -423,6 +425,27 @@
     }
 
     /**
+     * Used to notify that this process was frozen.
+     */
+    public void onProcessFrozen(long now,
+            ArrayMap<String, ProcessStateHolder> pkgList) {
+        mStateBeforeFrozen = mCurCombinedState % STATE_COUNT;
+        int currentMemFactor = mCurCombinedState / STATE_COUNT;
+        int combinedState = STATE_FROZEN + (currentMemFactor * STATE_COUNT);
+        setCombinedState(combinedState, now, pkgList);
+    }
+
+    /**
+     * Used to notify that this process was unfrozen.
+     */
+    public void onProcessUnfrozen(long now,
+            ArrayMap<String, ProcessStateHolder> pkgList) {
+        int currentMemFactor = mCurCombinedState / STATE_COUNT;
+        int combinedState = mStateBeforeFrozen + (currentMemFactor * STATE_COUNT);
+        setCombinedState(combinedState, now, pkgList);
+    }
+
+    /**
      * Update the current state of the given list of processes.
      *
      * @param state Current ActivityManager.PROCESS_STATE_*
@@ -434,13 +457,20 @@
             ArrayMap<String, ProcessStateHolder> pkgList) {
         if (state < 0) {
             state = mNumStartedServices > 0
-                    ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
+                    ? (STATE_SERVICE_RESTARTING + (memFactor * STATE_COUNT)) : STATE_NOTHING;
         } else {
-            state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
+            state = PROCESS_STATE_TO_STATE[state] + (memFactor * STATE_COUNT);
         }
+        setCombinedState(state, now, pkgList);
+    }
 
+    /**
+     * Sets combined state on the corresponding ProcessState objects.
+     */
+    void setCombinedState(int state, long now,
+            ArrayMap<String, ProcessStateHolder> pkgList) {
         // First update the common process.
-        mCommonProcess.setCombinedState(state, now);
+        mCommonProcess.setCombinedStateIdv(state, now);
 
         // If the common process is not multi-package, there is nothing else to do.
         if (!mCommonProcess.mMultiPackage) {
@@ -449,12 +479,15 @@
 
         if (pkgList != null) {
             for (int ip=pkgList.size()-1; ip>=0; ip--) {
-                pullFixedProc(pkgList, ip).setCombinedState(state, now);
+                pullFixedProc(pkgList, ip).setCombinedStateIdv(state, now);
             }
         }
     }
 
-    public void setCombinedState(int state, long now) {
+    /**
+     * Sets the combined state for this individual ProcessState object.
+     */
+    void setCombinedStateIdv(int state, long now) {
         ensureNotDead();
         if (!mDead && (mCurCombinedState != state)) {
             //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
@@ -545,7 +578,7 @@
         }
         mNumStartedServices++;
         if (mNumStartedServices == 1 && mCurCombinedState == STATE_NOTHING) {
-            setCombinedState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
+            setCombinedStateIdv(STATE_SERVICE_RESTARTING + (memFactor * STATE_COUNT), now);
         }
     }
 
@@ -561,7 +594,7 @@
         }
         mNumStartedServices--;
         if (mNumStartedServices == 0 && (mCurCombinedState %STATE_COUNT) == STATE_SERVICE_RESTARTING) {
-            setCombinedState(STATE_NOTHING, now);
+            setCombinedStateIdv(STATE_NOTHING, now);
         } else if (mNumStartedServices < 0) {
             Slog.wtfStack(TAG, "Proc started services underrun: pkg="
                     + mPackage + " uid=" + mUid + " name=" + mName);
@@ -1588,7 +1621,9 @@
                 case STATE_CACHED:
                     cachedMs += duration;
                     break;
-                    // TODO (b/261910877) Add support for tracking frozenMs.
+                case STATE_FROZEN:
+                    frozenMs += duration;
+                    break;
             }
         }
         statsEventOutput.write(
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 0a69ea8..2909b6a 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -118,9 +118,6 @@
      */
     public static final String NAS_DEFAULT_SERVICE = "nas_default_service";
 
-    /** (boolean) Whether notify() calls to NMS should acquire and hold WakeLocks. */
-    public static final String NOTIFY_WAKELOCK = "nms_notify_wakelock";
-
     // Flags related to media notifications
 
     /**
@@ -131,11 +128,6 @@
     // Flag related to Privacy Indicators
 
     /**
-     * Whether to show the complete ongoing app ops chip.
-     */
-    public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_2_enabled";
-
-    /**
      * Whether to show app ops chip for just microphone + camera.
      */
     public static final String PROPERTY_MIC_CAMERA_ENABLED = "camera_mic_icons_enabled";
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 9233050..8de448b 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -74,10 +74,6 @@
         public static final Flag LOG_DND_STATE_EVENTS =
                 releasedFlag("persist.sysui.notification.log_dnd_state_events");
 
-        /** Gating the holding of WakeLocks until NLSes are told about a new notification. */
-        public static final Flag WAKE_LOCK_FOR_POSTING_NOTIFICATION =
-                releasedFlag("persist.sysui.notification.wake_lock_for_posting_notification");
-
         /** Gating storing NotificationRankingUpdate ranking map in shared memory. */
         public static final Flag RANKING_UPDATE_ASHMEM = devFlag(
                 "persist.sysui.notification.ranking_update_ashmem");
diff --git a/core/java/com/android/internal/content/InstallLocationUtils.java b/core/java/com/android/internal/content/InstallLocationUtils.java
index a173ce1..f3dd0f8 100644
--- a/core/java/com/android/internal/content/InstallLocationUtils.java
+++ b/core/java/com/android/internal/content/InstallLocationUtils.java
@@ -454,8 +454,10 @@
         // Include raw dex metadata files
         sizeBytes += DexMetadataHelper.getPackageDexMetadataSize(pkg);
 
-        // Include all relevant native code
-        sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);
+        if (pkg.isExtractNativeLibs()) {
+            // Include all relevant native code
+            sizeBytes += NativeLibraryHelper.sumNativeBinariesWithOverride(handle, abiOverride);
+        }
 
         return sizeBytes;
     }
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index bb86801..3e16df4d 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1113,15 +1113,14 @@
             if (insets != null) {
                 mLastForceConsumingTypes = insets.getForceConsumingTypes();
 
-                @InsetsType int compatInsetsTypes =
+                final boolean clearsCompatInsets = clearsCompatInsets(attrs.type, attrs.flags,
+                        getResources().getConfiguration().windowConfiguration.getActivityType(),
+                        mLastForceConsumingTypes);
+                final @InsetsType int compatInsetsTypes =
                         WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout();
-                if (clearsCompatInsets(attrs.type, attrs.flags,
-                        getResources().getConfiguration().windowConfiguration.getWindowingMode())) {
-                    compatInsetsTypes &= mLastForceConsumingTypes;
-                }
                 final Insets stableBarInsets = insets.getInsetsIgnoringVisibility(
                         WindowInsets.Type.systemBars());
-                final Insets systemInsets = compatInsetsTypes == 0
+                final Insets systemInsets = clearsCompatInsets
                         ? Insets.NONE
                         : Insets.min(insets.getInsets(compatInsetsTypes), stableBarInsets);
                 mLastTopInset = systemInsets.top;
@@ -2625,8 +2624,7 @@
 
     @Override
     public String toString() {
-        return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
-                + getTitleSuffix(mWindow.getAttributes()) + "]";
+        return super.toString() + "[" + getTitleSuffix(mWindow.getAttributes()) + "]";
     }
 
     private static class ColorViewState {
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index aa2318d..483a184 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -1303,10 +1303,9 @@
             ScreenCapture.ScreenshotHardwareBuffer buffer) {
         t.setBuffer(layer, buffer.getHardwareBuffer());
         t.setDataSpace(layer, buffer.getColorSpace().getDataSpace());
-        // Avoid showing dimming effect for HDR content when running animation.
-        if (buffer.containsHdrLayers()) {
-            t.setDimmingEnabled(layer, false);
-        }
+        // Avoid showing dimming effect for HDR content when running animations.
+        // TODO(b/298219334): Only do this if we know we already dimmed in the screenshot
+        t.setDimmingEnabled(layer, false);
     }
 
     /** Returns whether the hardware buffer passed in is marked as protected. */
diff --git a/core/java/com/android/internal/security/TEST_MAPPING b/core/java/com/android/internal/security/TEST_MAPPING
index 2d598dc..0af3b03 100644
--- a/core/java/com/android/internal/security/TEST_MAPPING
+++ b/core/java/com/android/internal/security/TEST_MAPPING
@@ -12,10 +12,6 @@
       ]
     },
     {
-      "name": "ApkVerityTest",
-      "file_patterns": ["VerityUtils\\.java"]
-    },
-    {
       "name": "UpdatableSystemFontTest",
       "file_patterns": ["VerityUtils\\.java"]
     },
@@ -23,5 +19,11 @@
       "name": "CtsApkVerityInstallHostTestCases",
       "file_patterns": ["VerityUtils\\.java"]
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "FsVerityTest",
+      "file_patterns": ["VerityUtils\\.java"]
+    }
   ]
 }
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 116c301c..3e9458d 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -342,7 +342,11 @@
         synchronized (mLock) {
             int samplingInterval = properties.getInt(SETTINGS_SAMPLING_INTERVAL_KEY,
                     DEFAULT_SAMPLING_INTERVAL);
+            boolean wasEnabled = mEnabled;
             mEnabled = properties.getBoolean(SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
+            if (wasEnabled != mEnabled) {
+                Log.d(TAG, "Latency tracker " + (mEnabled ? "enabled" : "disabled") + ".");
+            }
             for (int action : ACTIONS_ALL) {
                 String actionName = getNameOfAction(STATSD_ACTION[action]).toLowerCase(Locale.ROOT);
                 int legacyActionTraceThreshold = properties.getInt(
diff --git a/core/java/com/android/internal/util/SettingsWrapper.java b/core/java/com/android/internal/util/SettingsWrapper.java
new file mode 100644
index 0000000..8cf6c18
--- /dev/null
+++ b/core/java/com/android/internal/util/SettingsWrapper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+/**
+ * A wrapper class for accessing and modifying system settings that would help with testing.
+ */
+public class SettingsWrapper {
+
+    /** Retrieves the string value of a system setting */
+    public String getStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+        return Settings.System.getStringForUser(contentResolver, name, userHandle);
+    }
+
+    /** Updates the string value of a system setting */
+    public String putStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+        return Settings.System.getStringForUser(contentResolver, name, userHandle);
+    }
+}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 21369f9..d6c5593 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -352,7 +352,7 @@
 
     const char* dirStr = env->GetStringUTFChars(internalDataDir, NULL);
     code->internalDataPathObj = dirStr;
-    code->internalDataPath = code->internalDataPathObj.string();
+    code->internalDataPath = code->internalDataPathObj.c_str();
     env->ReleaseStringUTFChars(internalDataDir, dirStr);
 
     if (externalDataDir != NULL) {
@@ -360,7 +360,7 @@
         code->externalDataPathObj = dirStr;
         env->ReleaseStringUTFChars(externalDataDir, dirStr);
     }
-    code->externalDataPath = code->externalDataPathObj.string();
+    code->externalDataPath = code->externalDataPathObj.c_str();
 
     code->sdkVersion = sdkVersion;
 
@@ -372,7 +372,7 @@
         code->obbPathObj = dirStr;
         env->ReleaseStringUTFChars(obbDir, dirStr);
     }
-    code->obbPath = code->obbPathObj.string();
+    code->obbPath = code->obbPathObj.c_str();
 
     jbyte* rawSavedState = NULL;
     jsize rawSavedSize = 0;
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index 339a7d3..5e096d7 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -106,15 +106,14 @@
             : NULL;
 
     if (path.length() < rootpath.length()) {
-        ALOGE("file path [%s] shorter than root path [%s]",
-                path.string(), rootpath.string());
+        ALOGE("file path [%s] shorter than root path [%s]", path.c_str(), rootpath.c_str());
         return (jint) -1;
     }
 
     off64_t tarSize = 0;
     jint err = write_tarfile(packageName, domain, rootpath, path, &tarSize, writer);
     if (!err) {
-        ALOGI("measured [%s] at %lld", path.string(), (long long)tarSize);
+        ALOGI("measured [%s] at %lld", path.c_str(), (long long)tarSize);
         env->CallVoidMethod(dataOutputObj, sFullBackupDataOutput.addSize, (jlong) tarSize);
     }
 
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 79fa2a2..fc081a7 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -76,7 +76,7 @@
             return err < 0 ? err : -1;
         }
         // TODO: Set the fields in the entity object
-        jstring keyStr = env->NewStringUTF(key.string());
+        jstring keyStr = env->NewStringUTF(key.c_str());
         env->SetObjectField(entity, s_keyField, keyStr);
         env->SetIntField(entity, s_dataSizeField, dataSize);
         return 0;
diff --git a/core/jni/android_backup_BackupHelperDispatcher.cpp b/core/jni/android_backup_BackupHelperDispatcher.cpp
index efe7d0b..efce8e1 100644
--- a/core/jni/android_backup_BackupHelperDispatcher.cpp
+++ b/core/jni/android_backup_BackupHelperDispatcher.cpp
@@ -118,7 +118,7 @@
     }
 
     env->SetIntField(headerObj, s_chunkSizeField, flattenedHeader.dataSize);
-    env->SetObjectField(headerObj, s_keyPrefixField, env->NewStringUTF(keyPrefix.string()));
+    env->SetObjectField(headerObj, s_keyPrefixField, env->NewStringUTF(keyPrefix.c_str()));
 
     return (jint) 0;
 }
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 2435406..c0e9215 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -58,13 +58,13 @@
     msg.appendFormat("Couldn't read row %d, col %d from CursorWindow.  "
             "Make sure the Cursor is initialized correctly before accessing data from it.",
             row, column);
-    jniThrowException(env, "java/lang/IllegalStateException", msg.string());
+    jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
 }
 
 static void throwUnknownTypeException(JNIEnv * env, jint type) {
     String8 msg;
     msg.appendFormat("UNKNOWN type %d", type);
-    jniThrowException(env, "java/lang/IllegalStateException", msg.string());
+    jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
 }
 
 static int getFdCount() {
@@ -89,7 +89,7 @@
     CursorWindow* window;
 
     const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
-    name.setTo(nameStr);
+    name = nameStr;
     env->ReleaseStringUTFChars(nameObj, nameStr);
 
     if (cursorWindowSize < 0) {
@@ -107,7 +107,7 @@
 fail:
     jniThrowExceptionFmt(env, "android/database/CursorWindowAllocationException",
                          "Could not allocate CursorWindow '%s' of size %d due to error %d.",
-                         name.string(), cursorWindowSize, status);
+                         name.c_str(), cursorWindowSize, status);
     return 0;
 }
 
@@ -139,7 +139,7 @@
 
 static jstring nativeGetName(JNIEnv* env, jclass clazz, jlong windowPtr) {
     CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
-    return env->NewStringUTF(window->name().string());
+    return env->NewStringUTF(window->name().c_str());
 }
 
 static void nativeWriteToParcel(JNIEnv * env, jclass clazz, jlong windowPtr,
@@ -151,7 +151,7 @@
     if (status) {
         String8 msg;
         msg.appendFormat("Could not write CursorWindow to Parcel due to error %d.", status);
-        jniThrowRuntimeException(env, msg.string());
+        jniThrowRuntimeException(env, msg.c_str());
     }
 }
 
@@ -267,7 +267,7 @@
         // doesn't like UTF-8 strings with high codepoints.  It actually expects
         // Modified UTF-8 with encoded surrogate pairs.
         String16 utf16(value, sizeIncludingNull - 1);
-        return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
+        return env->NewString(reinterpret_cast<const jchar*>(utf16.c_str()), utf16.size());
     } else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
         int64_t value = window->getFieldSlotValueLong(fieldSlot);
         char buf[32];
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index daa2087..c6a7511 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -229,7 +229,7 @@
             fullMessage.append(": ");
             fullMessage.append(message);
         }
-        jniThrowException(env, exceptionClass, fullMessage.string());
+        jniThrowException(env, exceptionClass, fullMessage.c_str());
     } else {
         jniThrowException(env, exceptionClass, message);
     }
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index 29520c2..893cc98 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -91,15 +91,14 @@
 // Called each time a statement begins execution, when tracing is enabled.
 static void sqliteTraceCallback(void *data, const char *sql) {
     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
-    ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n",
-            connection->label.string(), sql);
+    ALOG(LOG_VERBOSE, SQLITE_TRACE_TAG, "%s: \"%s\"\n", connection->label.c_str(), sql);
 }
 
 // Called each time a statement finishes execution, when profiling is enabled.
 static void sqliteProfileCallback(void *data, const char *sql, sqlite3_uint64 tm) {
     SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
-    ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n",
-            connection->label.string(), sql, tm * 0.000001f);
+    ALOG(LOG_VERBOSE, SQLITE_PROFILE_TAG, "%s: \"%s\" took %0.3f ms\n", connection->label.c_str(),
+         sql, tm * 0.000001f);
 }
 
 // Called after each SQLite VM instruction when cancelation is enabled.
@@ -130,7 +129,7 @@
     env->ReleaseStringUTFChars(labelStr, labelChars);
 
     sqlite3* db;
-    int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
+    int err = sqlite3_open_v2(path.c_str(), &db, sqliteFlags, NULL);
     if (err != SQLITE_OK) {
         throw_sqlite3_exception_errcode(env, err, "Could not open database");
         return 0;
@@ -180,7 +179,7 @@
         sqlite3_profile(db, &sqliteProfileCallback, connection);
     }
 
-    ALOGV("Opened connection %p with label '%s'", db, label.string());
+    ALOGV("Opened connection %p with label '%s'", db, label.c_str());
     return reinterpret_cast<jlong>(connection);
 }
 
@@ -760,7 +759,7 @@
     if (status) {
         String8 msg;
         msg.appendFormat("Failed to clear the cursor window, status=%d", status);
-        throw_sqlite3_exception(env, connection->db, msg.string());
+        throw_sqlite3_exception(env, connection->db, msg.c_str());
         return 0;
     }
 
@@ -770,7 +769,7 @@
         String8 msg;
         msg.appendFormat("Failed to set the cursor window column count to %d, status=%d",
                 numColumns, status);
-        throw_sqlite3_exception(env, connection->db, msg.string());
+        throw_sqlite3_exception(env, connection->db, msg.c_str());
         return 0;
     }
 
@@ -845,7 +844,7 @@
         String8 msg;
         msg.appendFormat("Row too big to fit into CursorWindow requiredPos=%d, totalRows=%d",
                 requiredPos, totalRows);
-        throw_sqlite3_exception(env, SQLITE_TOOBIG, NULL, msg.string());
+        throw_sqlite3_exception(env, SQLITE_TOOBIG, NULL, msg.c_str());
         return 0;
     }
 
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index 2ca4500..d36d29c 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -100,8 +100,8 @@
     if (array != NULL) {
         env->SetByteArrayRegion(array, 0,
                                 sizeof(header), reinterpret_cast<jbyte*>(&header));
-        env->SetByteArrayRegion(array, sizeof(header),
-                                maps.size(), reinterpret_cast<const jbyte*>(maps.string()));
+        env->SetByteArrayRegion(array, sizeof(header), maps.size(),
+                                reinterpret_cast<const jbyte*>(maps.c_str()));
         env->SetByteArrayRegion(array, sizeof(header) + maps.size(),
                                 header.allocSize, reinterpret_cast<jbyte*>(leak_info.buffer));
     }
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 1c59742..5f3a1b5 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -874,11 +874,11 @@
     if (camera == 0) return 0;
 
     String8 params8 = camera->getParameters();
-    if (params8.isEmpty()) {
+    if (params8.empty()) {
         jniThrowRuntimeException(env, "getParameters failed (empty parameters)");
         return 0;
     }
-    return env->NewStringUTF(params8.string());
+    return env->NewStringUTF(params8.c_str());
 }
 
 static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index 5293c58..041fed7 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -514,7 +514,7 @@
         ssize_t res;
         while ((res = TEMP_FAILURE_RETRY(read(readFd, &out[0], /*count*/1))) > 0) {
             if (out[0] == '\n') {
-                ALOGD("%s", logLine.string());
+                ALOGD("%s", logLine.c_str());
                 logLine.clear();
             } else {
                 logLine.append(out);
@@ -526,8 +526,8 @@
                     "Failed to read from fd (errno = %#x, message = '%s')",
                     errno, strerror(errno));
             //return;
-        } else if (!logLine.isEmpty()) {
-            ALOGD("%s", logLine.string());
+        } else if (!logLine.empty()) {
+            ALOGD("%s", logLine.c_str());
         }
 
         close(readFd);
@@ -956,8 +956,8 @@
         return OK;
     } else if (!res.isOk()) {
         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
-        ALOGE("%s: Failed to setup vendor tag descriptors: %s",
-                __FUNCTION__, res.toString8().string());
+        ALOGE("%s: Failed to setup vendor tag descriptors: %s", __FUNCTION__,
+              res.toString8().c_str());
         return res.serviceSpecificErrorCode();
     }
     if (0 < desc->getTagCount()) {
@@ -971,8 +971,8 @@
             return OK;
         } else if (!res.isOk()) {
             VendorTagDescriptorCache::clearGlobalVendorTagCache();
-            ALOGE("%s: Failed to setup vendor tag cache: %s",
-                    __FUNCTION__, res.toString8().string());
+            ALOGE("%s: Failed to setup vendor tag cache: %s", __FUNCTION__,
+                  res.toString8().c_str());
             return res.serviceSpecificErrorCode();
         }
 
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index c947fba..30e546c 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1543,7 +1543,8 @@
         String8 captureTime = nativeContext->getCaptureTime();
 
         if (writer->addEntry(TAG_DATETIME, NativeContext::DATETIME_COUNT,
-                reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) {
+                             reinterpret_cast<const uint8_t*>(captureTime.c_str()),
+                             TIFF_IFD_0) != OK) {
             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                     "Invalid metadata for tag %x", TAG_DATETIME);
             return nullptr;
@@ -1551,7 +1552,8 @@
 
         // datetime original
         if (writer->addEntry(TAG_DATETIMEORIGINAL, NativeContext::DATETIME_COUNT,
-                reinterpret_cast<const uint8_t*>(captureTime.string()), TIFF_IFD_0) != OK) {
+                             reinterpret_cast<const uint8_t*>(captureTime.c_str()),
+                             TIFF_IFD_0) != OK) {
             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                     "Invalid metadata for tag %x", TAG_DATETIMEORIGINAL);
             return nullptr;
@@ -1879,8 +1881,10 @@
         cameraModel += brand.c_str();
 
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
-                reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
-                TAG_UNIQUECAMERAMODEL, writer);
+                                                     reinterpret_cast<const uint8_t*>(
+                                                             cameraModel.c_str()),
+                                                     TIFF_IFD_0),
+                                    env, TAG_UNIQUECAMERAMODEL, writer);
     }
 
     {
@@ -2165,7 +2169,8 @@
         String8 description = nativeContext->getDescription();
         size_t len = description.bytes() + 1;
         if (writer->addEntry(TAG_IMAGEDESCRIPTION, len,
-                reinterpret_cast<const uint8_t*>(description.string()), TIFF_IFD_0) != OK) {
+                             reinterpret_cast<const uint8_t*>(description.c_str()),
+                             TIFF_IFD_0) != OK) {
             jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                     "Invalid metadata for tag %x", TAG_IMAGEDESCRIPTION);
         }
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index ccae67f..6440cc3 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2071,10 +2071,67 @@
                           mixerBehavior);
 }
 
-static jint convertAudioMixToNative(JNIEnv *env,
-                                    AudioMix *nAudioMix,
-                                    const jobject jAudioMix)
-{
+static jint convertAudioMixingRuleToNative(JNIEnv *env, const jobject audioMixingRule,
+                                           std::vector<AudioMixMatchCriterion> *nCriteria) {
+    jobject jRuleCriteria = env->GetObjectField(audioMixingRule, gAudioMixingRuleFields.mCriteria);
+
+    jobjectArray jCriteria = static_cast<jobjectArray>(
+            env->CallObjectMethod(jRuleCriteria, gArrayListMethods.toArray));
+    env->DeleteLocalRef(jRuleCriteria);
+
+    jint numCriteria = env->GetArrayLength(jCriteria);
+    if (numCriteria > MAX_CRITERIA_PER_MIX) {
+        numCriteria = MAX_CRITERIA_PER_MIX;
+    }
+
+    nCriteria->resize(numCriteria);
+    for (jint i = 0; i < numCriteria; i++) {
+        AudioMixMatchCriterion &nCriterion = (*nCriteria)[i];
+
+        jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
+
+        nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
+
+        const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
+        switch (match_rule) {
+            case RULE_MATCH_UID:
+                nCriterion.mValue.mUid =
+                        env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
+                break;
+            case RULE_MATCH_USERID:
+                nCriterion.mValue.mUserId =
+                        env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
+                break;
+            case RULE_MATCH_AUDIO_SESSION_ID: {
+                jint jAudioSessionId =
+                        env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
+                nCriterion.mValue.mAudioSessionId = static_cast<audio_session_t>(jAudioSessionId);
+            } break;
+            case RULE_MATCH_ATTRIBUTE_USAGE:
+            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
+                jobject jAttributes =
+                        env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
+
+                auto paa = JNIAudioAttributeHelper::makeUnique();
+                jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAttributes, paa.get());
+                if (jStatus != AUDIO_JAVA_SUCCESS) {
+                    return jStatus;
+                }
+                if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
+                    nCriterion.mValue.mUsage = paa->usage;
+                } else {
+                    nCriterion.mValue.mSource = paa->source;
+                }
+                env->DeleteLocalRef(jAttributes);
+            } break;
+        }
+        env->DeleteLocalRef(jCriterion);
+    }
+    env->DeleteLocalRef(jCriteria);
+    return AUDIO_JAVA_SUCCESS;
+}
+
+static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, const jobject jAudioMix) {
     nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
     nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
     nAudioMix->mDeviceType =
@@ -2094,69 +2151,16 @@
     env->DeleteLocalRef(jFormat);
 
     jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
-    jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria);
     nAudioMix->mAllowPrivilegedMediaPlaybackCapture =
             env->GetBooleanField(jRule, gAudioMixingRuleFields.mAllowPrivilegedPlaybackCapture);
     nAudioMix->mVoiceCommunicationCaptureAllowed =
             env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed);
+
+    jint status = convertAudioMixingRuleToNative(env, jRule, &(nAudioMix->mCriteria));
+
     env->DeleteLocalRef(jRule);
-    jobjectArray jCriteria = static_cast<jobjectArray>(
-            env->CallObjectMethod(jRuleCriteria, gArrayListMethods.toArray));
-    env->DeleteLocalRef(jRuleCriteria);
 
-    jint numCriteria = env->GetArrayLength(jCriteria);
-    if (numCriteria > MAX_CRITERIA_PER_MIX) {
-        numCriteria = MAX_CRITERIA_PER_MIX;
-    }
-
-    for (jint i = 0; i < numCriteria; i++) {
-        AudioMixMatchCriterion nCriterion;
-
-        jobject jCriterion = env->GetObjectArrayElement(jCriteria, i);
-
-        nCriterion.mRule = env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mRule);
-
-        const uint32_t match_rule = nCriterion.mRule & ~RULE_EXCLUSION_MASK;
-        switch (match_rule) {
-        case RULE_MATCH_UID:
-            nCriterion.mValue.mUid = env->GetIntField(jCriterion,
-                    gAudioMixMatchCriterionFields.mIntProp);
-            break;
-        case RULE_MATCH_USERID:
-            nCriterion.mValue.mUserId =
-                    env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
-            break;
-        case RULE_MATCH_AUDIO_SESSION_ID: {
-            jint jAudioSessionId =
-                    env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
-            nCriterion.mValue.mAudioSessionId = static_cast<audio_session_t>(jAudioSessionId);
-        } break;
-        case RULE_MATCH_ATTRIBUTE_USAGE:
-        case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
-            jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
-
-            auto paa = JNIAudioAttributeHelper::makeUnique();
-            jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAttributes, paa.get());
-            if (jStatus != AUDIO_JAVA_SUCCESS) {
-                    return jStatus;
-            }
-            if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
-                nCriterion.mValue.mUsage = paa->usage;
-            } else {
-                nCriterion.mValue.mSource = paa->source;
-            }
-            env->DeleteLocalRef(jAttributes);
-            }
-            break;
-        }
-
-        nAudioMix->mCriteria.push_back(nCriterion);
-        env->DeleteLocalRef(jCriterion);
-    }
-
-    env->DeleteLocalRef(jCriteria);
-
-    return AUDIO_JAVA_SUCCESS;
+    return status;
 }
 
 static jint
@@ -2200,6 +2204,45 @@
     return nativeToJavaStatus(status);
 }
 
+static jint android_media_AudioSystem_updatePolicyMixes(JNIEnv *env, jobject clazz,
+                                                        jobjectArray mixes,
+                                                        jobjectArray updatedMixingRules) {
+    if (mixes == nullptr || updatedMixingRules == nullptr) {
+        return AUDIO_JAVA_BAD_VALUE;
+    }
+
+    jsize updatesCount = env->GetArrayLength(mixes);
+    if (updatesCount == 0 || updatesCount != env->GetArrayLength(updatedMixingRules)) {
+        return AUDIO_JAVA_BAD_VALUE;
+    }
+
+    std::vector<std::pair<AudioMix, std::vector<AudioMixMatchCriterion>>> updates(updatesCount);
+    for (int i = 0; i < updatesCount; i++) {
+        jobject jAudioMix = env->GetObjectArrayElement(mixes, i);
+        jobject jAudioMixingRule = env->GetObjectArrayElement(updatedMixingRules, i);
+        if (!env->IsInstanceOf(jAudioMix, gAudioMixClass) ||
+            !env->IsInstanceOf(jAudioMixingRule, gAudioMixingRuleClass)) {
+            return AUDIO_JAVA_BAD_VALUE;
+        }
+
+        jint ret;
+        if ((ret = convertAudioMixToNative(env, &updates[i].first, jAudioMix)) !=
+            AUDIO_JAVA_SUCCESS) {
+            return ret;
+        }
+        if ((ret = convertAudioMixingRuleToNative(env, jAudioMixingRule, &updates[i].second)) !=
+            AUDIO_JAVA_SUCCESS) {
+            return ret;
+        }
+    }
+
+    ALOGV("AudioSystem::updatePolicyMixes numMixes %d", updatesCount);
+    int status = AudioSystem::updatePolicyMixes(updates);
+    ALOGV("AudioSystem::updatePolicyMixes returned %d", status);
+
+    return nativeToJavaStatus(status);
+}
+
 static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz,
         jint uid, jintArray deviceTypes, jobjectArray deviceAddresses) {
     AudioDeviceTypeAddrVector deviceVector;
@@ -3158,6 +3201,10 @@
          MAKE_AUDIO_SYSTEM_METHOD(getAudioHwSyncForSession),
          MAKE_JNI_NATIVE_METHOD("registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
                                 android_media_AudioSystem_registerPolicyMixes),
+         MAKE_JNI_NATIVE_METHOD("updatePolicyMixes",
+                                "([Landroid/media/audiopolicy/AudioMix;[Landroid/media/audiopolicy/"
+                                "AudioMixingRule;)I",
+                                android_media_AudioSystem_updatePolicyMixes),
          MAKE_JNI_NATIVE_METHOD("setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
                                 android_media_AudioSystem_setUidDeviceAffinities),
          MAKE_AUDIO_SYSTEM_METHOD(removeUidDeviceAffinities),
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 4c4443f..0e3c510 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -285,7 +285,7 @@
         hardware::Parcel *parcel =
             JHwParcel::GetNativeContext(env, thiz)->getParcel();
 
-        status_t err = parcel->writeInterfaceToken(nameCopy.string());
+        status_t err = parcel->writeInterfaceToken(nameCopy.c_str());
         signalExceptionForError(env, err);
     }
 }
@@ -687,9 +687,7 @@
 static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) {
     String16 utf16String(s.c_str(), s.size());
 
-    return env->NewString(
-            reinterpret_cast<const jchar *>(utf16String.string()),
-            utf16String.size());
+    return env->NewString(reinterpret_cast<const jchar *>(utf16String.c_str()), utf16String.size());
 }
 
 static jstring JHwParcel_native_readString(JNIEnv *env, jobject thiz) {
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
index eda5075..43a8be1 100644
--- a/core/jni/android_os_UEventObserver.cpp
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -51,8 +51,8 @@
         const char* field = buffer;
         const char* end = buffer + length + 1;
         do {
-            if (strstr(field, match.string())) {
-                ALOGV("Matched uevent message with pattern: %s", match.string());
+            if (strstr(field, match.c_str())) {
+                ALOGV("Matched uevent message with pattern: %s", match.c_str());
                 return true;
             }
             field += strlen(field) + 1;
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 9dce5e3..6ed0a8a 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -953,8 +953,10 @@
             String8 msg;
             msg.appendFormat("Unknown binder error code. 0x%" PRIx32, err);
             // RemoteException is a checked exception, only throw from certain methods.
-            jniThrowException(env, canThrowRemoteException
-                    ? "android/os/RemoteException" : "java/lang/RuntimeException", msg.string());
+            jniThrowException(env,
+                              canThrowRemoteException ? "android/os/RemoteException"
+                                                      : "java/lang/RuntimeException",
+                              msg.c_str());
             break;
     }
 }
@@ -1286,8 +1288,7 @@
     IBinder* target = getBPNativeData(env, obj)->mObject.get();
     if (target != NULL) {
         const String16& desc = target->getInterfaceDescriptor();
-        return env->NewString(reinterpret_cast<const jchar*>(desc.string()),
-                              desc.size());
+        return env->NewString(reinterpret_cast<const jchar*>(desc.c_str()), desc.size());
     }
     jniThrowException(env, "java/lang/RuntimeException",
             "No binder found for object");
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 4f2bf4a..18c60a7 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -148,7 +148,7 @@
 
     const size_t N = name8.size();
     if (N > 0) {
-        const char* str = name8.string();
+        const char* str = name8.c_str();
         for (size_t i=0; i<N; i++) {
             if (str[i] < '0' || str[i] > '9') {
                 struct passwd* pwd = getpwnam(str);
@@ -180,7 +180,7 @@
 
     const size_t N = name8.size();
     if (N > 0) {
-        const char* str = name8.string();
+        const char* str = name8.c_str();
         for (size_t i=0; i<N; i++) {
             if (str[i] < '0' || str[i] > '9') {
                 struct group* grp = getgrnam(str);
@@ -583,8 +583,8 @@
         env->ReleaseStringCritical(name, str);
     }
 
-    if (!name8.isEmpty()) {
-        AndroidRuntime::getRuntime()->setArgv0(name8.string(), true /* setProcName */);
+    if (!name8.empty()) {
+        AndroidRuntime::getRuntime()->setArgv0(name8.c_str(), true /* setProcName */);
     }
 }
 
@@ -690,7 +690,7 @@
         return;
     }
 
-    int fd = open(file.string(), O_RDONLY | O_CLOEXEC);
+    int fd = open(file.c_str(), O_RDONLY | O_CLOEXEC);
 
     if (fd >= 0) {
         //ALOGI("Clearing %" PRId32 " sizes", count);
@@ -704,7 +704,7 @@
         close(fd);
 
         if (len < 0) {
-            ALOGW("Unable to read %s", file.string());
+            ALOGW("Unable to read %s", file.c_str());
             len = 0;
         }
         buffer[len] = 0;
@@ -717,7 +717,7 @@
             //ALOGI("Parsing at: %s", p);
             for (i=0; i<count; i++) {
                 const String8& field = fields[i];
-                if (strncmp(p, field.string(), field.length()) == 0) {
+                if (strncmp(p, field.c_str(), field.length()) == 0) {
                     p += field.length();
                     while (*p == ' ' || *p == '\t') p++;
                     char* num = p;
@@ -729,7 +729,7 @@
                     }
                     char* end;
                     sizesArray[i] = strtoll(num, &end, 10);
-                    //ALOGI("Field %s = %" PRId64, field.string(), sizesArray[i]);
+                    // ALOGI("Field %s = %" PRId64, field.c_str(), sizesArray[i]);
                     foundCount++;
                     break;
                 }
@@ -746,7 +746,7 @@
 
         free(buffer);
     } else {
-        ALOGW("Unable to open %s", file.string());
+        ALOGW("Unable to open %s", file.c_str());
     }
 
     //ALOGI("Done!");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dd1a499..d898a23 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2094,6 +2094,16 @@
     <permission android:name="android.permission.MANAGE_TEST_NETWORKS"
         android:protectionLevel="signature" />
 
+    <!-- Allows direct access to the <RemoteAuth>Service interfaces.
+         @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+    <permission android:name="android.permission.MANAGE_REMOTE_AUTH"
+                android:protectionLevel="signature" />
+
+    <!-- Allows direct access to the <RemoteAuth>Service authentication methods.
+         @hide @TestApi @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES) -->
+    <permission android:name="android.permission.USE_REMOTE_AUTH"
+                android:protectionLevel="signature" />
+
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
diff --git a/core/res/OWNERS b/core/res/OWNERS
index b46902e..0df7c20 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -52,3 +52,6 @@
 # Telephony
 per-file res/values/config_telephony.xml = file:/platform/frameworks/opt/telephony:/OWNERS
 per-file res/xml/sms_short_codes.xml = file:/platform/frameworks/opt/telephony:/OWNERS
+
+# TV Input Framework
+per-file res/values/config_tv_external_input_logging.xml = file:/services/core/java/com/android/server/tv/OWNERS
diff --git a/core/res/res/layout/autofill_fill_dialog.xml b/core/res/res/layout/autofill_fill_dialog.xml
index d1a4935..37d2fa0 100644
--- a/core/res/res/layout/autofill_fill_dialog.xml
+++ b/core/res/res/layout/autofill_fill_dialog.xml
@@ -85,14 +85,18 @@
         android:layout_marginStart="24dp"
         android:layout_marginEnd="24dp"
         android:theme="@style/Theme.DeviceDefault.AutofillHalfScreenDialogButton"
-        android:orientation="horizontal">
+        android:orientation="horizontal"
+        android:gravity="center_vertical">
 
         <Button
             android:id="@+id/autofill_dialog_no"
             android:layout_width="wrap_content"
-            android:layout_height="36dp"
-            android:layout_marginTop="6dp"
-            android:layout_marginBottom="6dp"
+            android:layout_height="40dp"
+            android:paddingStart="12dp"
+            android:paddingEnd="12dp"
+            android:paddingTop="0dp"
+            android:paddingBottom="0dp"
+            android:minWidth="0dp"
             style="?android:attr/borderlessButtonStyle"
             android:text="@string/autofill_save_no">
         </Button>
@@ -107,9 +111,8 @@
         <Button
             android:id="@+id/autofill_dialog_yes"
             android:layout_width="wrap_content"
-            android:layout_height="36dp"
-            android:layout_marginTop="6dp"
-            android:layout_marginBottom="6dp"
+            android:layout_height="40dp"
+            android:minWidth="0dp"
             style="@style/AutofillHalfSheetTonalButton"
             android:text="@string/autofill_save_yes"
             android:visibility="gone" >
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 85529d6..bed19a8 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -72,14 +72,18 @@
             android:layout_marginTop="32dp"
             android:layout_marginBottom="18dp"
             android:theme="@style/Theme.DeviceDefault.AutofillHalfScreenDialogButton"
-            android:orientation="horizontal">
+            android:orientation="horizontal"
+            android:gravity="center_vertical">
 
             <Button
                 android:id="@+id/autofill_save_no"
                 android:layout_width="wrap_content"
-                android:layout_height="36dp"
-                android:layout_marginTop="6dp"
-                android:layout_marginBottom="6dp"
+                android:layout_height="40dp"
+                android:paddingStart="12dp"
+                android:paddingEnd="12dp"
+                android:paddingTop="0dp"
+                android:paddingBottom="0dp"
+                android:minWidth="0dp"
                 style="?android:attr/borderlessButtonStyle"
                 android:text="@string/autofill_save_no">
             </Button>
@@ -94,9 +98,8 @@
             <Button
                 android:id="@+id/autofill_save_yes"
                 android:layout_width="wrap_content"
-                android:layout_height="36dp"
-                android:layout_marginTop="6dp"
-                android:layout_marginBottom="6dp"
+                android:layout_height="40dp"
+                android:minWidth="0dp"
                 style="@style/AutofillHalfSheetTonalButton"
                 android:text="@string/autofill_save_yes">
             </Button>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 46fb80c..b1caec2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2e werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3e werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kloon <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privaat <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Vra PIN voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vra ontsluitpatroon voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vra wagwoord voordat jy ontspeld"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Dateer op in "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Dateer <xliff:g id="TYPE">%1$s</xliff:g> op in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Dateer <xliff:g id="TYPE_0">%1$s</xliff:g> en <xliff:g id="TYPE_1">%2$s</xliff:g> op in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Dateer hierdie items op in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> en <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Stoor"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nee, dankie"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Nie nou nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 40246bef..8109e9a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2ኛ ሥራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3ኛ ሥራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g>ን አባዛ"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ከመንቀል በፊት ፒን ጠይቅ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ከመንቀል በፊት የማስከፈቻ ስርዓተ-ጥለት ጠይቅ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"በ"<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ውስጥ ይዘመን?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> በ"<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ውስጥ ይዘመን?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> እና <xliff:g id="TYPE_1">%2$s</xliff:g> በ"<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ውስጥ ይዘመኑ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"እነዚህ ንጥሎች በ"<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ውስጥ ይዘመኑ፦ <xliff:g id="TYPE_0">%1$s</xliff:g>፣ <xliff:g id="TYPE_1">%2$s</xliff:g> እና <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"አስቀምጥ"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"አይ፣ አመሰግናለሁ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"አሁን አይደለም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 0286d42..ff1ecdc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1871,6 +1871,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"العمل الثاني <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"العمل الثالث <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"نسخة طبق الأصل عن \"<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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"طلب إدخال رقم التعريف الشخصي قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"طلب إدخال النقش الخاص بإلغاء القفل قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"طلب إدخال كلمة المرور قبل إزالة التثبيت"</string>
@@ -2035,8 +2036,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"هل تريد التحديث في "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"؟"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"هل تريد تحديث <xliff:g id="TYPE">%1$s</xliff:g> في "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"؟"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"هل تريد تحديث <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> في "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"؟"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"هل تريد تعديل هذه العناصر في "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g> و<xliff:g id="TYPE_1">%2$s</xliff:g> و<xliff:g id="TYPE_2">%3$s</xliff:g>؟"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"حفظ"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"لا، شكرًا"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ليس الآن"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a1679b3..f2aee40 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"২য় কার্য <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"৩য় কার্য <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"ক্ল’ন <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"আনপিন কৰাৰ পূৰ্বে পিন দিবলৈ কওক"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"আনপিন কৰাৰ পূৰ্বে আনলক আৰ্হি দিবলৈ কওক"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"আনপিন কৰাৰ পূৰ্বে পাছৱৰ্ড দিবলৈ কওক"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"ত আপডে’ট কৰিবনে?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"ত <xliff:g id="TYPE">%1$s</xliff:g> আপডে’ট কৰিবনে?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"ত <xliff:g id="TYPE_0">%1$s</xliff:g> আৰু <xliff:g id="TYPE_1">%2$s</xliff:g> আপডে’ট কৰিবনে?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"এই তথ্যবোৰ "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> আৰু <xliff:g id="TYPE_2">%3$s</xliff:g>ত আপডে’ট কৰিবনে?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"ছেভ কৰক"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"নালাগে, ধন্যবাদ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"এতিয়া নহয়"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 49a599e..0004ba8 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-ci İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-cü İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kopyalayın: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Şəxsi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Ayırmadan öncə PIN istənilsin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Qrafik açar istənilsin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ayırmadan öncə parol istənilsin"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ünvanında yenilənsin?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ünvanında yenilənsin?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> və <xliff:g id="TYPE_1">%2$s</xliff:g> "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ünvanında yenilənsin?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> və <xliff:g id="TYPE_2">%3$s</xliff:g> bölmələrində bu elementlər yenilənsin?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Yadda saxlayın"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Xeyr, çox sağ olun"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"İndi yox"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 97483a4..592c344 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -494,7 +494,7 @@
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji da šalje komande SIM kartici. To je veoma opasno."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičkih aktivnosti"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može da prepozna fizičke aktivnosti."</string>
-    <string name="permlab_camera" msgid="6320282492904119413">"snimanje fotografija i video snimaka"</string>
+    <string name="permlab_camera" msgid="6320282492904119413">"snimanje fotografija i videa"</string>
     <string name="permdesc_camera" msgid="5240801376168647151">"Ova aplikacija može da snima slike i video snimke pomoću kamere dok se aplikacija koristi."</string>
     <string name="permlab_backgroundCamera" msgid="7549917926079731681">"da snima slike i video snimke u pozadini"</string>
     <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ova aplikacija može da snima fotografije i video snimke pomoću kamere u bilo kom trenutku."</string>
@@ -745,8 +745,8 @@
     <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Omogućava aplikaciji da čita video fajlove iz deljenog memorijskog prostora."</string>
     <string name="permlab_readMediaImages" msgid="4057590631020986789">"čitanje fajlova slika iz deljenog memorijskog prostora"</string>
     <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Omogućava aplikaciji da čita fajlove slika iz deljenog memorijskog prostora."</string>
-    <string name="permlab_readVisualUserSelect" msgid="5516204215354667586">"čitanje fajlova slika i video snimaka koje korisnik bira iz deljenog memorijskog prostora"</string>
-    <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Omogućava aplikaciji da čita fajlove slika i video snimaka koje izaberete iz deljenog memorijskog prostora."</string>
+    <string name="permlab_readVisualUserSelect" msgid="5516204215354667586">"čitanje fajlova slika i videa koje korisnik bira iz deljenog memorijskog prostora"</string>
+    <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Omogućava aplikaciji da čita fajlove slika i videa koje izaberete iz deljenog memorijskog prostora."</string>
     <string name="permlab_sdcardWrite" msgid="4863021819671416668">"menjanje ili brisanje sadržaja deljenog memorijskog prostora"</string>
     <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Dozvoljava aplikaciji da upisuje sadržaj deljenog memorijskog prostora."</string>
     <string name="permlab_use_sip" msgid="8250774565189337477">"upućivanje/prijem SIP poziva"</string>
@@ -1172,7 +1172,7 @@
     <string name="app_running_notification_text" msgid="5120815883400228566">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
     <string name="ok" msgid="2646370155170753815">"Potvrdi"</string>
     <string name="cancel" msgid="6908697720451760115">"Otkaži"</string>
-    <string name="yes" msgid="9069828999585032361">"Potvrdi"</string>
+    <string name="yes" msgid="9069828999585032361">"U redu"</string>
     <string name="no" msgid="5122037903299899715">"Otkaži"</string>
     <string name="dialog_alert_title" msgid="651856561974090712">"Pažnja"</string>
     <string name="loading" msgid="3138021523725055037">"Učitava se…"</string>
@@ -1417,7 +1417,7 @@
     <string name="ext_media_new_notification_message" msgid="6095403121990786986">"Dodirnite da biste podesili"</string>
     <string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"Izaberite da biste podesili"</string>
     <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"Možda morate da reformatirate uređaj. Dodirnite da biste izbacili."</string>
-    <string name="ext_media_ready_notification_message" msgid="7509496364380197369">"Za čuvanje slika, video snimaka, muzike i drugog sadržaja"</string>
+    <string name="ext_media_ready_notification_message" msgid="7509496364380197369">"Za čuvanje slika, videa, muzike i drugog sadržaja"</string>
     <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"Pregledajte medijske fajlove"</string>
     <string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"Problem sa: <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> ne radi"</string>
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. poslovni imejl <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kloniraj <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privatni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Traži PIN pre otkačinjanja"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži šablon za otključavanje pre otkačinjanja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži lozinku pre otkačinjanja"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Želite li da ažurirate u usluzi "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Želite li da ažurirate stavku <xliff:g id="TYPE">%1$s</xliff:g> u usluzi "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Želite li da ažurirate stavke <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> u usluzi "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Želite li da ažurirate ove stavke u usluzi "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Sačuvaj"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ne, hvala"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ne sada"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index cd87b52..4cd8aa58 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -671,14 +671,10 @@
   </string-array>
     <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Нешта пайшло не так. Паўтарыце спробу."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок адбіткаў пальцаў"</string>
-    <!-- no translation found for device_unlock_notification_name (2632928999862915709) -->
-    <skip />
-    <!-- no translation found for alternative_unlock_setup_notification_title (6241508547901933544) -->
-    <skip />
-    <!-- no translation found for alternative_face_setup_notification_content (3384959224091897331) -->
-    <skip />
-    <!-- no translation found for alternative_fp_setup_notification_content (7454096947415721639) -->
-    <skip />
+    <string name="device_unlock_notification_name" msgid="2632928999862915709">"Разблакіроўка прылады"</string>
+    <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Паспрабуйце іншы спосаб разблакіроўкі"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Выкарыстоўвайце распазнаванне твару, калі прылада не распазнае ваш адбітак пальца. Гэта функцыя можа прыдацца, напрыклад, калі ў вас мокрыя пальцы."</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Выкарыстоўвайце разблакіроўку адбіткам пальца, калі прылада не распазнае ваш твар. Гэта функцыя можа прыдацца, напрыклад, ва ўмовах недастатковай асветленасці."</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Распазнаванне твару"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Праблема з распазнаваннем твару"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Націсніце, каб выдаліць мадэль твару, пасля дадайце твар яшчэ раз"</string>
@@ -1873,6 +1869,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Другая праца <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Трэцяя праца <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Кланіраваць \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Запытваць PIN-код перад адмацаваннем"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запытваць узор разблакіроўкі перад адмацаваннем"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запытваць пароль перад адмацаваннем"</string>
@@ -2037,8 +2035,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Абнавіць у сэрвісе "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Абнавіць даныя \"<xliff:g id="TYPE">%1$s</xliff:g>\" у сэрвісе "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Абнавіць даныя \"<xliff:g id="TYPE_0">%1$s</xliff:g>\" і \"<xliff:g id="TYPE_1">%2$s</xliff:g>\" у сэрвісе "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Абнавіць наступныя даныя ў сэрвісе "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> і <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Захаваць"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Не, дзякуй"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Не зараз"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 7810776..97345fc 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Втори служебен профил (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Трети служебен профил (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Копие на <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Запитване за ПИН код преди освобождаване"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитване за фигура за отключване преди освобождаване"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитване за парола преди освобождаване"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Искате ли да актуализирате в(ъв) "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Искате ли да актуализирате <xliff:g id="TYPE">%1$s</xliff:g> в(ъв) "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Искате ли да актуализирате <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> в(ъв) "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Искате ли да актуализирате тези елементи в(ъв) "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Запазване"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Не, благодаря"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Не сега"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 02bfaae..1d1e29c 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"দ্বিতীয় কার্যক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"তৃতীয় কার্যক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> ক্লোন"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"আনপিন করার আগে পিন চান"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"আনপিন করার আগে আনলক প্যাটার্ন চান"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"আনপিন করার আগে পাসওয়ার্ড চান"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"-এ আপডেট করতে চান?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"-এ <xliff:g id="TYPE">%1$s</xliff:g> আপডেট করতে চান?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"-এ <xliff:g id="TYPE_0">%1$s</xliff:g> এবং <xliff:g id="TYPE_1">%2$s</xliff:g> আপডেট করতে চান?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"এইসব আইটেম "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"-এ আপডেট করতে চান: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ও <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"সেভ করুন"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"না থাক"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"এখনই নয়"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 00aa307..3fd0637 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kloniranje aplikacije <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> – privatno"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Traži PIN prije nego se otkači"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži uzorak za otključavanje prije poništavanja kačenja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži lozinku prije nego se otkači"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Ažurirati u "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Ažurirati <xliff:g id="TYPE">%1$s</xliff:g> u "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Ažurirati <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> u "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Ažurirati ove stavke u oznaci "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Sačuvaj"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ne, hvala"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ne sada"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 42e631b..5ec91f5 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1868,6 +1868,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2n <xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3r <xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clon de <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Sol·licita el PIN per deixar de fixar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Sol·licita el patró de desbloqueig per deixar de fixar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demana la contrasenya per deixar de fixar"</string>
@@ -2032,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Vols actualitzar-ho a "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Vols actualitzar <xliff:g id="TYPE">%1$s</xliff:g> a "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Vols actualitzar <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> a "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Vols actualitzar aquests elements a "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Desa"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, gràcies"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ara no"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 772ef53..89d2501 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1869,6 +1869,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klon <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Soukromá aplikace <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Před uvolněním požádat o PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Před uvolněním požádat o bezpečnostní gesto"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Před odepnutím požádat o heslo"</string>
@@ -2033,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Aktualizovat ve službě "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Aktualizovat údaj <xliff:g id="TYPE">%1$s</xliff:g> ve službě "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Aktualizovat údaje <xliff:g id="TYPE_0">%1$s</xliff:g> a <xliff:g id="TYPE_1">%2$s</xliff:g> ve službě "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Aktualizovat tyto položky ve službě "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Uložit"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ne, děkuji"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Teď ne"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 697800b..ca2206c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -671,12 +671,12 @@
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeraftryk"</string>
     <string name="device_unlock_notification_name" msgid="2632928999862915709">"Enhedsoplåsning"</string>
     <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Prøv en anden metode til oplåsning"</string>
-    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Brug ansigtslås, hvis dit fingeraftryk ikke genkendes, f.eks. når du har våde fingre"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Brug ansigtsoplåsning, hvis dit fingeraftryk ikke genkendes, f.eks. når du har våde fingre"</string>
     <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Brug oplåsning med fingeraftryk, hvis dit ansigt ikke genkendes, f.eks. når der ikke er nok lys"</string>
-    <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansigtslås"</string>
-    <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Der er et problem med Ansigtslås"</string>
+    <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansigtsoplåsning"</string>
+    <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Der er et problem med Ansigtsoplåsning"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Tryk for at slette din ansigtsmodel, og tilføj derefter dit ansigt igen"</string>
-    <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Hvis du vil bruge ansigtslåsen, skal du aktivere "<b>"Kameraadgang"</b>" under Indstillinger &gt; Privatliv"</string>
+    <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Hvis du vil bruge ansigtsoplåsning, skal du aktivere "<b>"Kameraadgang"</b>" under Indstillinger &gt; Privatliv"</string>
     <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Oplåsning med fingeraftryk"</string>
     <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Fingeraftrykssensoren kan ikke bruges"</string>
     <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Få den repareret."</string>
@@ -710,19 +710,19 @@
   <string-array name="face_acquired_vendor">
   </string-array>
     <string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansigt ikke verificeret. Hardware ikke tilgængelig."</string>
-    <string name="face_error_timeout" msgid="2598544068593889762">"Prøv ansigtslås igen"</string>
+    <string name="face_error_timeout" msgid="2598544068593889762">"Prøv ansigtsoplåsning igen"</string>
     <string name="face_error_no_space" msgid="5649264057026021723">"Der kan ikke gemmes nye ansigtsdata. Slet et gammelt først."</string>
     <string name="face_error_canceled" msgid="2164434737103802131">"Ansigtshandlingen blev annulleret."</string>
-    <string name="face_error_user_canceled" msgid="5766472033202928373">"Ansigtslås blev annulleret af brugeren"</string>
+    <string name="face_error_user_canceled" msgid="5766472033202928373">"Ansigtsoplåsning blev annulleret af brugeren"</string>
     <string name="face_error_lockout" msgid="7864408714994529437">"Du har prøvet for mange gange. Prøv igen senere."</string>
-    <string name="face_error_lockout_permanent" msgid="8533257333130473422">"Du har brugt for mange forsøg. Ansigtslås er utilgængelig."</string>
+    <string name="face_error_lockout_permanent" msgid="8533257333130473422">"Du har brugt for mange forsøg. Ansigtsoplåsning er utilgængelig."</string>
     <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Du har brugt for mange forsøg. Angiv skærmlåsen i stedet."</string>
     <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ansigtet kan ikke genkendes. Prøv igen."</string>
-    <string name="face_error_not_enrolled" msgid="1134739108536328412">"Du har ikke konfigureret ansigtslås."</string>
-    <string name="face_error_hw_not_present" msgid="7940978724978763011">"Ansigtslås understøttes ikke på denne enhed"</string>
+    <string name="face_error_not_enrolled" msgid="1134739108536328412">"Du har ikke konfigureret ansigtsoplåsning."</string>
+    <string name="face_error_hw_not_present" msgid="7940978724978763011">"Ansigtsoplåsning understøttes ikke på denne enhed"</string>
     <string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidigt deaktiveret."</string>
     <string name="face_name_template" msgid="3877037340223318119">"Ansigt <xliff:g id="FACEID">%d</xliff:g>"</string>
-    <string name="face_app_setting_name" msgid="5854024256907828015">"Brug ansigtslås"</string>
+    <string name="face_app_setting_name" msgid="5854024256907828015">"Brug ansigtsoplåsning"</string>
     <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Brug ansigts- eller skærmlås"</string>
     <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Brug dit ansigt for at fortsætte"</string>
     <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Brug din ansigts- eller skærmlås for at fortsætte"</string>
@@ -975,7 +975,7 @@
     <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv igen"</string>
     <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Prøv igen"</string>
     <string name="lockscreen_storage_locked" msgid="634993789186443380">"Lås op for at se alle funktioner og data"</string>
-    <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Det maksimale antal forsøg på at bruge ansigtslås er overskredet"</string>
+    <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Det maksimale antal forsøg på at bruge ansigtsoplåsning er overskredet"</string>
     <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"Intet SIM-kort"</string>
     <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"Intet SIM-kort i tabletten."</string>
     <string name="lockscreen_missing_sim_message" product="tv" msgid="3903140876952198273">"Intet SIM-kort i din Android TV-enhed."</string>
@@ -1045,7 +1045,7 @@
     <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Udvid oplåsningsområdet."</string>
     <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lås op ved at stryge."</string>
     <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås op med mønster."</string>
-    <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Ansigtslås."</string>
+    <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Ansigtsoplåsning."</string>
     <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Lås op med pinkode."</string>
     <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Lås op ved hjælp af pinkoden til SIM-kortet."</string>
     <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Lås op ved hjælp af PUK-koden til SIM-kortet."</string>
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. <xliff:g id="LABEL">%1$s</xliff:g> til arbejde"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klon af <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Bed om pinkode inden frigørelse"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Bed om oplåsningsmønster ved deaktivering"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Bed om adgangskode inden frigørelse"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Vil du opdatere i "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Vil du opdatere <xliff:g id="TYPE">%1$s</xliff:g> i "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Vil du opdatere <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> i "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Vil du opdatere disse elementer i "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Gem"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nej tak"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ikke nu"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b5e38b9..be511e8 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -669,14 +669,10 @@
   </string-array>
     <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Ein Problem ist aufgetreten. Versuch es noch einmal."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerabdruck-Symbol"</string>
-    <!-- no translation found for device_unlock_notification_name (2632928999862915709) -->
-    <skip />
-    <!-- no translation found for alternative_unlock_setup_notification_title (6241508547901933544) -->
-    <skip />
-    <!-- no translation found for alternative_face_setup_notification_content (3384959224091897331) -->
-    <skip />
-    <!-- no translation found for alternative_fp_setup_notification_content (7454096947415721639) -->
-    <skip />
+    <string name="device_unlock_notification_name" msgid="2632928999862915709">"Geräteentsperrung"</string>
+    <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Andere Entsperrungsart verwenden"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Verwende die Entsperrung per Gesichtserkennung, wenn dein Fingerabdruck nicht erkannt wird, beispielsweise wenn deine Finger nass sind"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Verwende die Entsperrung per Fingerabdruck, wenn dein Gesicht nicht erkannt wird, beispielsweise wenn es zu dunkel ist"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Entsperrung per Gesichtserkennung"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem bei der Entsperrung per Gesichtserkennung"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Tippe, um dein Gesichtsmodell zu löschen, und füge es dann noch einmal hinzu"</string>
@@ -1871,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. <xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. <xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klon <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Vor dem Beenden nach PIN fragen"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vor dem Beenden nach Entsperrungsmuster fragen"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vor dem Beenden nach Passwort fragen"</string>
@@ -2035,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"In "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" aktualisieren?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" aktualisieren?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> und <xliff:g id="TYPE_1">%2$s</xliff:g> in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" aktualisieren?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> und <xliff:g id="TYPE_2">%3$s</xliff:g> in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" aktualisieren?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Speichern"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nein danke"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Nicht jetzt"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a0a4474..1d3471c 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> εργασίας 2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> εργασίας 3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Κλώνος <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Να γίνεται ερώτηση για το μοτίβο ξεκλειδώματος, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Να γίνεται ερώτηση για τον κωδικό πρόσβασης, πριν από το ξεκαρφίτσωμα"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Ενημέρωση σε "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>";"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Ενημέρωση <xliff:g id="TYPE">%1$s</xliff:g> σε "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>";"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Ενημέρωση <xliff:g id="TYPE_0">%1$s</xliff:g> και <xliff:g id="TYPE_1">%2$s</xliff:g> σε "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>";"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Ενημέρωση αυτών των στοιχείων στο "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> και <xliff:g id="TYPE_2">%3$s</xliff:g>;"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Αποθήκευση"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Όχι, ευχαριστώ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Όχι τώρα"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index a931c58..8c33f16 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3rd Work <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">"Private <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Update in "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Update <xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Update <xliff:g id="TYPE_0">%1$s</xliff:g> and <xliff:g id="TYPE_1">%2$s</xliff:g> in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Update these items in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, and <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Save"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, thanks"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Not now"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 1d657c7..6dc9ce4 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3rd Work <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">"Private <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Update in "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Update <xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Update <xliff:g id="TYPE_0">%1$s</xliff:g> and <xliff:g id="TYPE_1">%2$s</xliff:g> in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Update these items in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, and <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Save"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No thanks"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Not now"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 275b1bc..3daab6c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3rd Work <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">"Private <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Update in "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Update <xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Update <xliff:g id="TYPE_0">%1$s</xliff:g> and <xliff:g id="TYPE_1">%2$s</xliff:g> in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Update these items in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, and <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Save"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, thanks"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Not now"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 3504a53..67ebab1 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2nd Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3rd Work <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">"Private <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Update in "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Update <xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Update <xliff:g id="TYPE_0">%1$s</xliff:g> and <xliff:g id="TYPE_1">%2$s</xliff:g> in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Update these items in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, and <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Save"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, thanks"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Not now"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 9a72749..d8b5016 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎2nd Work ‎‏‎‎‏‏‎<xliff:g id="LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‎3rd Work ‎‏‎‎‏‏‎<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">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎Private ‎‏‎‎‏‏‎<xliff:g id="LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎Ask for PIN before unpinning‎‏‎‎‏‎"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎Ask for unlock pattern before unpinning‎‏‎‎‏‎"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎Ask for password before unpinning‎‏‎‎‏‎"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎Update in ‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LABEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎Update ‎‏‎‎‏‏‎<xliff:g id="TYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ in ‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LABEL">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎Update ‎‏‎‎‏‏‎<xliff:g id="TYPE_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="TYPE_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎ in ‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LABEL">%3$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‎‎Update these items in ‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LABEL">%4$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎: ‎‏‎‎‏‏‎<xliff:g id="TYPE_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="TYPE_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎, and ‎‏‎‎‏‏‎<xliff:g id="TYPE_2">%3$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎Save‎‏‎‎‏‎"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎No thanks‎‏‎‎‏‎"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎Not now‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8b651d1..e0aeb31 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clon de <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> privado"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para quitar fijación"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar desbloqueo para quitar fijación"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para quitar fijación"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"¿Quieres actualizar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"¿Quieres actualizar <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"¿Quieres actualizar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"¿Quieres actualizar estos elementos en "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> y <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Guardar"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, gracias"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ahora no"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9c678c5..3bcc0f4 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1868,6 +1868,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo 3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clon de <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para desactivar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir patrón de desbloqueo para dejar de fijar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para desactivar"</string>
@@ -2032,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"¿Actualizar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"¿Actualizar <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"¿Actualizar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"¿Actualizar estos elementos en "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> y <xliff:g id="TYPE_2">%3$s</xliff:g>)?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Guardar"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, gracias"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ahora no"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index c17a179..d212946 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Rakenduse <xliff:g id="LABEL">%1$s</xliff:g> kloon"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privaatne <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Enne vabastamist küsi PIN-koodi"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Enne vabastamist küsi avamismustrit"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Enne vabastamist küsi parooli"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Kas värskendada üksust teenuses "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Kas värskendada üksust <xliff:g id="TYPE">%1$s</xliff:g> teenuses "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Kas värskendada üksusi <xliff:g id="TYPE_0">%1$s</xliff:g> ja <xliff:g id="TYPE_1">%2$s</xliff:g> teenuses "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Kas värskendada teenuses "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" neid üksusi: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ja <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salvesta"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Tänan, ei"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Hiljem"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 7a6fa1d..302acb0 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -669,14 +669,10 @@
   </string-array>
     <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Arazo bat izan da. Saiatu berriro."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string>
-    <!-- no translation found for device_unlock_notification_name (2632928999862915709) -->
-    <skip />
-    <!-- no translation found for alternative_unlock_setup_notification_title (6241508547901933544) -->
-    <skip />
-    <!-- no translation found for alternative_face_setup_notification_content (3384959224091897331) -->
-    <skip />
-    <!-- no translation found for alternative_fp_setup_notification_content (7454096947415721639) -->
-    <skip />
+    <string name="device_unlock_notification_name" msgid="2632928999862915709">"Gailua desblokeatzea"</string>
+    <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Probatu gailua desblokeatzeko beste modu bat"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Erabili Aurpegi bidez desblokeatzea hatz-marka ezagutzen ez denean (adibidez, hatzak bustita dauzkazunean)"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Erabili Hatz-marka bidez desblokeatzea aurpegia ezagutzen ez denean (adibidez, argi nahikorik ez dagoenean)"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Aurpegi bidez desblokeatzea"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arazoak ditugu aurpegi bidez desblokeatzeko eginbidearekin"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Sakatu hau aurpegi-eredua ezabatzeko eta, gero, gehitu aurpegia berriro"</string>
@@ -1871,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Laneko 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Laneko 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> aplikazioaren klona"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Eskatu PINa aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Eskatu pasahitza aingura kendu aurretik"</string>
@@ -2035,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" zerbitzuan eguneratu nahi duzu?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" zerbitzuan eguneratu nahi duzu <xliff:g id="TYPE">%1$s</xliff:g>?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" zerbitzuan eguneratu nahi dituzu <xliff:g id="TYPE_0">%1$s</xliff:g> eta <xliff:g id="TYPE_1">%2$s</xliff:g>?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" zerbitzuan eguneratu nahi dituzu <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> eta <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Gorde"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ez, eskerrik asko"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Orain ez"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index c733bea..7947b6e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1133,9 +1133,9 @@
     <string name="duration_hours_relative_future" msgid="6670440478481140565">"{count,plural, =1{# ساعت}one{# ساعت}other{# ساعت}}"</string>
     <string name="duration_days_relative_future" msgid="8870658635774250746">"{count,plural, =1{# روز}one{# روز}other{# روز}}"</string>
     <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# سال}one{# سال}other{# سال}}"</string>
-    <string name="VideoView_error_title" msgid="5750686717225068016">"مشکل در ویدئو"</string>
-    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"متأسفیم، این ویدئو برای پخش جریانی با این دستگاه معتبر نیست."</string>
-    <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"پخش این ویدئو ممکن نیست."</string>
+    <string name="VideoView_error_title" msgid="5750686717225068016">"مشکل در ویدیو"</string>
+    <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"متأسفیم، این ویدیو برای پخش جریانی با این دستگاه معتبر نیست."</string>
+    <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"پخش این ویدیو ممکن نیست."</string>
     <string name="VideoView_error_button" msgid="5138809446603764272">"تأیید"</string>
     <string name="relative_time" msgid="8572030016028033243">"<xliff:g id="DATE">%1$s</xliff:g>، <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="8365974533050605886">"ظهر"</string>
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"کار دوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"کار سوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"همسانه <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"درخواست کد پین قبل از برداشتن پین"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی بازگشایی قفل قبل‌از برداشتن سنجاق"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"درخواست گذرواژه قبل از برداشتن سنجاق"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"در "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" به‌روزرسانی شود؟"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> در "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" به‌روزرسانی شود؟"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> و <xliff:g id="TYPE_1">%2$s</xliff:g> در "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" به‌روزرسانی شود؟"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"این موارد در "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>، <xliff:g id="TYPE_1">%2$s</xliff:g>، و <xliff:g id="TYPE_2">%3$s</xliff:g> به‌روزرسانی شود؟"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"ذخیره"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"نه سپاسگزارم"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"حالا نه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5cf1c99..3b5c86e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Toinen <xliff:g id="LABEL">%1$s</xliff:g>, työ"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Kolmas <xliff:g id="LABEL">%1$s</xliff:g>, työ"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kloonaa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pyydä PIN ennen irrotusta"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pyydä salasana ennen irrotusta"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Päivitetäänkö "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Päivitetäänkö <xliff:g id="TYPE">%1$s</xliff:g> ("<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>")?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Päivitetäänkö <xliff:g id="TYPE_0">%1$s</xliff:g> ja <xliff:g id="TYPE_1">%2$s</xliff:g> ("<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>")?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Päivitetäänkö nämä ("<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"): <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ja <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Tallenna"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ei kiitos"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ei nyt"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index fda1183..782ccd0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clone de <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> privé"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Demander le NIP avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Mettre à jour sous "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Mettre à jour <xliff:g id="TYPE">%1$s</xliff:g> sous "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Mettre à jour <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> sous "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Mettre à jour ces éléments sous "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" : <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> et <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Enregistrer"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Non, merci"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Pas maintenant"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 654a3f2..b5ea2e2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1868,6 +1868,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnelle"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnelle"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Cloner <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Demander le code avant de retirer l\'épingle"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant de retirer l\'épingle"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant de retirer l\'épingle"</string>
@@ -2032,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Mettre à jour cet élément dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Mettre à jour <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Mettre à jour <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Mettre à jour ces éléments dans "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" : <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> et <xliff:g id="TYPE_2">%3$s</xliff:g> ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Enregistrer"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Non, merci"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Pas maintenant"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 51006b9..ea3f104 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clonar <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pedir PIN antes de soltar a fixación"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrón de desbloqueo antes de soltar a fixación"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir contrasinal antes de soltar a fixación"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Queres actualizar o contido en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Queres actualizar <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Queres actualizar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Queres actualizar estes datos (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>) en "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Gardar"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Non, grazas"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Agora non"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index aa2a887..0a42b24 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2જું કાર્ય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3જું કાર્ય <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g>ની ક્લોન"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"અનપિન કરતા પહેલાં પિન માટે પૂછો"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"અનપિન કરતા પહેલાં અનલૉક પૅટર્ન માટે પૂછો"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"અનપિન કરતાં પહેલાં પાસવર્ડ માટે પૂછો"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"માં અપડેટ કરીએ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g>ને "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"માં અપડેટ કરીએ?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> અને <xliff:g id="TYPE_1">%2$s</xliff:g>ને "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"માં અપડેટ કરીએ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"શું "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"માંની: આ <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> અને <xliff:g id="TYPE_2">%3$s</xliff:g> આઇટમને અપડેટ કરીએ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"સાચવો"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ના, આભાર"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"હમણાં નહીં"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a81ada6..8a383a1 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"दूसरा काम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"तीसरा काम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> का क्लोन"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"अनपिन करने से पहले पिन के लिए पूछें"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन करने से पहले लॉक खोलने के पैटर्न के लिए पूछें"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"अनपिन करने से पहले पासवर्ड के लिए पूछें"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"क्या आप "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" में अपडेट करना चाहते हैं?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"क्या आप "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" में <xliff:g id="TYPE">%1$s</xliff:g> अपडेट करना चाहते हैं?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"क्या आप "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" में <xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> अपडेट करना चाहते हैं?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"क्या आपको "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" में इन आइटम को अपडेट करना है: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, और <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"सेव करें"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"नहीं, धन्यवाद"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"अभी नहीं"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index fefddbc..d7f5b4a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. <xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. <xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kloniraj <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privatno <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Traži PIN radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži uzorak za otključavanje radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži zaporku radi otkvačivanja"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Želite li ažurirati u oznaku "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Želite li ažurirati podatke <xliff:g id="TYPE">%1$s</xliff:g> u oznaci "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Želite li ažurirati podatke <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> u oznaci "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Želite li ažurirati ove stavke u oznaci "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Spremi"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ne, hvala"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ne sad"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8c8b38f..57b81a0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> klónozása"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privát <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"PIN-kód kérése a kitűzés feloldásához"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Feloldási minta kérése a rögzítés feloldásához"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Jelszó kérése a rögzítés feloldásához"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Frissíti a(z) "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" szolgáltatásban?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Frissíti a(z) "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" szolgáltatásban a következőt: <xliff:g id="TYPE">%1$s</xliff:g>?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Frissíti a(z) "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" szolgáltatásban a következőket: <xliff:g id="TYPE_0">%1$s</xliff:g> és <xliff:g id="TYPE_1">%2$s</xliff:g>?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Frissíti a(z) "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" szolgáltatásban a következőket: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> és <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Mentés"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nem, köszönöm"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ne most"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index e240c31..59827cb 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-րդ աշխատանք <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g>-ի կլոն"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Հարցնել PIN կոդը"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Հարցնել ապակողպող նախշը"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Հարցնել գաղտնաբառը"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Թարմացնե՞լ "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ծառայությունում"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Թարմացնե՞լ տվյալները (<xliff:g id="TYPE">%1$s</xliff:g>) "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ծառայությունում"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Թարմացնե՞լ տվյալները (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>) "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ծառայությունում"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Թարմացնե՞լ տվյալները (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g>) "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ծառայությունում"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Պահել"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ոչ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ոչ հիմա"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 5a9188d..8603809 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1643,7 +1643,7 @@
     <string name="media_route_status_in_use" msgid="6684112905244944724">"Sedang digunakan"</string>
     <string name="display_manager_built_in_display_name" msgid="1015775198829722440">"Layar Built-In"</string>
     <string name="display_manager_hdmi_display_name" msgid="1022758026251534975">"Layar HDMI"</string>
-    <string name="display_manager_overlay_display_name" msgid="5306088205181005861">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <string name="display_manager_overlay_display_name" msgid="5306088205181005861">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
     <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", aman"</string>
     <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"Lupa Pola?"</string>
@@ -1867,6 +1867,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="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>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Perbarui di "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Perbarui <xliff:g id="TYPE">%1$s</xliff:g> di "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Perbarui <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> di "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Perbarui item-item berikut di "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, dan <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Simpan"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Lain kali"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Lain kali"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 8ea6f6a..7420a25 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu (2)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu (3)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Afrit af <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Biðja um PIN-númer til að losa"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Biðja um opnunarmynstur til að losa"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Biðja um aðgangsorð til að losa"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Uppfæra í "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Uppfæra <xliff:g id="TYPE">%1$s</xliff:g> í "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Uppfæra <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> í "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Uppfæra þessi atriði í "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Vista"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nei, takk"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ekki núna"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index eb0b569..168a161 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> di lavoro (2°)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> di lavoro (3°)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> (clone)"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"<xliff:g id="LABEL">%1$s</xliff:g> privato"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Richiedi il PIN per lo sblocco"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Richiedi sequenza di sblocco prima di sbloccare"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Richiedi password prima di sbloccare"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Vuoi aggiornare su "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Vuoi aggiornare <xliff:g id="TYPE">%1$s</xliff:g> su "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Vuoi aggiornare <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> su "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Vuoi aggiornare i seguenti dati in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salva"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"No, grazie"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Non ora"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index a3ffd39..1f90994 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1868,6 +1868,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> שני בעבודה"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> שלישי בעבודה"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"שכפול של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"יש לבקש קוד אימות לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"צריך לבקש קו ביטול נעילה לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"יש לבקש סיסמה לפני ביטול הצמדה"</string>
@@ -1956,7 +1958,7 @@
     <string name="app_suspended_more_details" msgid="211260942831587014">"מידע נוסף"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ביטול ההשהיה של האפליקציה"</string>
     <string name="work_mode_off_title" msgid="6367463960165135829">"להפעיל את האפליקציות לעבודה?"</string>
-    <string name="work_mode_turn_on" msgid="5316648862401307800">"הפעלה"</string>
+    <string name="work_mode_turn_on" msgid="5316648862401307800">"ביטול ההשהיה"</string>
     <string name="work_mode_emergency_call_button" msgid="6818855962881612322">"שיחת חירום"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
@@ -2032,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"לעדכן בשירות "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"לעדכן <xliff:g id="TYPE">%1$s</xliff:g> בשירות "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"האם לעדכן את <xliff:g id="TYPE_0">%1$s</xliff:g> ואת <xliff:g id="TYPE_1">%2$s</xliff:g> ב-"<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"לעדכן את הפריטים אלה ב-"<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>":‏ <xliff:g id="TYPE_0">%1$s</xliff:g>,‏ <xliff:g id="TYPE_1">%2$s</xliff:g> ו-<xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"שמירה"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"לא, תודה"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"לא עכשיו"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index aa4ac4e..d761875 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -321,7 +321,7 @@
     <string name="permgrouplab_camera" msgid="9090413408963547706">"カメラ"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"写真と動画の撮影"</string>
     <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"付近のデバイス"</string>
-    <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"付近のデバイスの検出と接続"</string>
+    <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"付近のデバイスの\\n検出と接続"</string>
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"通話履歴"</string>
     <string name="permgroupdesc_calllog" msgid="2026996642917801803">"通話履歴の読み取りと書き込み"</string>
     <string name="permgrouplab_phone" msgid="570318944091926620">"電話"</string>
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 番目の仕事用<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"オフライン再生を解除する前にPINの入力を求める"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"オフライン再生を解除する前にパスワードの入力を求める"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" で更新しますか?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g>を "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" で更新しますか?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>を "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" で更新しますか?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>、<xliff:g id="TYPE_2">%3$s</xliff:g>を "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" で更新しますか?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"はい"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"いいえ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"後で"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 9e730df..513b392 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"მე-2 სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"მე-3 სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"გსურთ "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"-ში განახლება?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"გსურთ, "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"-ში განაახლოთ <xliff:g id="TYPE">%1$s</xliff:g>?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"გსურთ, "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"-ში განაახლოთ <xliff:g id="TYPE_0">%1$s</xliff:g> და <xliff:g id="TYPE_1">%2$s</xliff:g>?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"განახლდეს ეს ერთეულები "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"-ში: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> და <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"შენახვა"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"არა, გმადლობთ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ახლა არა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 1561045..1d93a71 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-ші жұмыс профилі (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-ші жұмыс профилі (<xliff:g id="LABEL">%1$s</xliff:g>)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> клондау"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Босату алдында PIN кодын сұрау"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Босату алдында бекітпесін ашу өрнегін сұрау"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Босату алдында құпия сөзді сұрау"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" қызметінде жаңартылсын ба?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> деректері "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" қызметінде жаңартылсын ба?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> және <xliff:g id="TYPE_1">%2$s</xliff:g> деректері "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" қызметінде жаңартылсын ба?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" қызметіндегі <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> және <xliff:g id="TYPE_2">%3$s</xliff:g> деректері жаңартылсын ба?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Сақтау"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Жоқ, рақмет"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Қазір емес"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index cea9af4..9047666 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"ក្លូន <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> ឯកជន"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"សួរ​រក​កូដ PIN មុន​ពេលដកខ្ទាស់"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"សួរ​រក​លំនាំ​ដោះ​សោ​មុន​ពេលដោះខ្ទាស់"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"សួរ​រក​ពាក្យ​សម្ងាត់​មុន​ពេល​ផ្ដាច់"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"ធ្វើ​បច្ចុប្បន្នភាព​នៅក្នុង "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"ធ្វើ​បច្ចុប្បន្នភាព <xliff:g id="TYPE">%1$s</xliff:g> នៅក្នុង "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"ធ្វើ​បច្ចុប្បន្នភាព​ <xliff:g id="TYPE_0">%1$s</xliff:g> និង <xliff:g id="TYPE_1">%2$s</xliff:g> នៅក្នុង "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ធ្វើ​បច្ចុប្បន្នភាព​ធាតុ​ទាំងនេះ​នៅក្នុង "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"៖ <xliff:g id="TYPE_0">%1$s</xliff:g> <xliff:g id="TYPE_1">%2$s</xliff:g> និង<xliff:g id="TYPE_2">%3$s</xliff:g>ឬ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"រក្សាទុក"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ទេ អរគុណ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"កុំ​ទាន់"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 4cdb755..19c6f5d 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 ನೇ ಕೆಲಸದ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 ನೇ ಕೆಲಸದ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಿನ್‌ ಕೇಳು"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅನ್‌ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಕೇಳಿ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್ ಕೇಳು"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ನಲ್ಲಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಬೇಕೆ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> ಅನ್ನು "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ನಲ್ಲಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಬೇಕೆ?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> ಮತ್ತು <xliff:g id="TYPE_1">%2$s</xliff:g> ಅನ್ನು "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ನಲ್ಲಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಬೇಕೆ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ಈ ಮುಂದಿನ ಐಟಂಗಳನ್ನು "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ನಲ್ಲಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಬೇಕೆ: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ಮತ್ತು <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"ಉಳಿಸಿ"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ಬೇಡ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ಸದ್ಯಕ್ಕೆ ಬೇಡ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ae92aa9..335a957 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"두 번째 업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"세 번째 업무용<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> 복사"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"고정 해제 이전에 PIN 요청"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"고정 해제 시 잠금 해제 패턴 요청"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"고정 해제 이전에 비밀번호 요청"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"에서 업데이트하시겠습니까?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"에서 <xliff:g id="TYPE">%1$s</xliff:g>을(를) 업데이트하시겠습니까?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"에서 <xliff:g id="TYPE_0">%1$s</xliff:g> 및 <xliff:g id="TYPE_1">%2$s</xliff:g>을(를) 업데이트하시겠습니까?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"에서 <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> 항목을 업데이트하시겠습니까?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"저장"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"사용 안함"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"나중에"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c585841d..df4929f 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> клону"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бошотуудан мурун PIN суралсын"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бошотуудан мурун графикалык ачкыч суралсын"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Бошотуудан мурун сырсөз суралсын"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" кызматында жаңыртылсынбы?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" кызматындагы <xliff:g id="TYPE">%1$s</xliff:g> жаңыртылсын?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" кызматындагы <xliff:g id="TYPE_0">%1$s</xliff:g> жана <xliff:g id="TYPE_1">%2$s</xliff:g> жаңыртылсынбы?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" кызматындагы төмөнкүлөр жаңыртылсынбы: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> жана <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Сактоо"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Жок, рахмат"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Азыр эмес"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 8057449..cddabaf 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"ບ່ອນເຮັດວຽກທີ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"ບ່ອນເຮັດວຽກທີ 3 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"ໂຄລນ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"​ຖາມ​ຫາ PIN ກ່ອນ​ຍົກ​ເລີກ​ການປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"​ຖາມ​ຫາ​ຮູບ​ແບບ​ປົດ​ລັອກ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"​ຖາມ​ຫາ​ລະ​ຫັດ​ຜ່ານ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"ອັບເດດໃນ "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ບໍ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"ອັບເດດ <xliff:g id="TYPE">%1$s</xliff:g> ໃນ "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ບໍ?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"ອັບເດດ <xliff:g id="TYPE_0">%1$s</xliff:g> ແລະ <xliff:g id="TYPE_1">%2$s</xliff:g> ໃນ "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ບໍ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ອັບເດດລາຍການເຫຼົ່ານີ້ໃນ "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ແລະ <xliff:g id="TYPE_2">%3$s</xliff:g> ບໍ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"ບັນທຶກ"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ບໍ່, ຂອບໃຈ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ບໍ່ຟ້າວເທື່ອ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c6d36d1..3316845 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1869,6 +1869,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-asis darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-iasis darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"„<xliff:g id="LABEL">%1$s</xliff:g>“ kopija"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privat. „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Prašyti PIN kodo prieš atsegant"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Prašyti atrakinimo piešinio prieš atsegant"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Prašyti slaptažodžio prieš atsegant"</string>
@@ -2033,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Atnaujinti paslaugoje "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Atnaujinti <xliff:g id="TYPE">%1$s</xliff:g> paslaugoje "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Atnaujinti <xliff:g id="TYPE_0">%1$s</xliff:g> ir <xliff:g id="TYPE_1">%2$s</xliff:g> paslaugoje "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Atnaujinti šiuos elementus paslaugoje "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ir <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Išsaugoti"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ne, ačiū"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ne dabar"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 45b9586..fb1b7b9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1868,6 +1868,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. darba profils: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. darba profils: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> (klons)"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Prasīt PIN kodu pirms atspraušanas"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pirms atspraušanas pieprasīt atbloķēšanas kombināciju"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pirms atspraušanas pieprasīt paroli"</string>
@@ -2032,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Vai atjaunināt informāciju pakalpojumā "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Vai atjaunināt informāciju <xliff:g id="TYPE">%1$s</xliff:g> pakalpojumā "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Vai atjaunināt informāciju <xliff:g id="TYPE_0">%1$s</xliff:g> un <xliff:g id="TYPE_1">%2$s</xliff:g> pakalpojumā "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Vai atjaunināt šos vienumus pakalpojumā "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> un <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Saglabāt"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nē, paldies"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Vēlāk"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 33e9a55..ae0a035 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Втора деловна <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Трета деловна <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Клонирајте го <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Побарај PIN пред откачување"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Побарај шема за откл. пред откачување"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Побарај лозинка пред откачување"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Да се ажурира во "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Да се ажурира <xliff:g id="TYPE">%1$s</xliff:g> во "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Да се ажурираат <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> во "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Да се ажурираат овие ставки во "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Зачувај"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Не, фала"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Не сега"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 8a4ddf1..80e8061 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"രണ്ടാമത്തെ ഔദ്യോഗിക <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"മൂന്നാമത്തെ ഔദ്യോഗിക <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"ക്ലോൺ <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ചെയ്യുംമുമ്പ് പിൻ ചോദിക്കൂ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"അൺപിന്നിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടൂ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"അൺപിന്നിനുമുമ്പ് പാസ്‌വേഡ് ആവശ്യപ്പെടൂ"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" എന്നതിൽ അപ്‌ഡേറ്റ് ചെയ്യണോ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g>, "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" എന്നതിൽ അപ്‌ഡേറ്റ് ചെയ്യണോ?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> എന്നിവ "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" എന്നതിൽ അപ്‌ഡേറ്റ് ചെയ്യണോ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ഇനിപ്പറയുന്ന ഇനങ്ങൾ "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" എന്നതിൽ അപ്‌ഡേറ്റ് ചെയ്യണോ: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g> ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"സംരക്ഷിക്കുക"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"വേണ്ട, നന്ദി"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ഇപ്പോൾ വേണ്ട"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 8332bb1..d2bdb4d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -971,7 +971,7 @@
     <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Тайлах хээгээ зурна уу"</string>
     <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Яаралтай тусламж"</string>
     <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Дуудлагаруу буцах"</string>
-    <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Зөв!"</string>
+    <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Зөв"</string>
     <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дахин оролдох"</string>
     <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Дахин оролдох"</string>
     <string name="lockscreen_storage_locked" msgid="634993789186443380">"Бүх онцлог, өгөгдлийн түгжээг тайлах"</string>
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Клон <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бэхэлснийг болиулахаасаа өмнө ПИН асуух"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бэхэлснийг болиулахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"-д шинэчлэх үү?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g>-г "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"-д шинэчлэх үү?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> болон <xliff:g id="TYPE_1">%2$s</xliff:g>-г "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"-д шинэчлэх үү?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"-н эдгээр зүйлийг шинэчлэх: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> болон <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Хадгалах"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Үгүй, баярлалаа"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Одоо биш"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index effddd6..5f7a5c1 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> क्लोन केलेले"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"अनपिन करण्‍यापूर्वी पिन विचारा"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन करण्‍यापूर्वी अनलॉक नमुन्यासाठी विचारा"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"अनपिन करण्‍यापूर्वी संकेतशब्दासाठी विचारा"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" मध्ये अपडेट करायचे का?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g>, "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" मध्ये अपडेट करायचे का?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> आणि <xliff:g id="TYPE_1">%2$s</xliff:g>, "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" मध्ये अपडेट करायचे का?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"हे आयटम "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> आणि <xliff:g id="TYPE_2">%3$s</xliff:g> मध्ये अपडेट करायचे आहेत का?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"सेव्ह करा"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"नाही, नको"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"आता नको"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index bcaa06d..74e904d 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> kerja ke-2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> kerja ke-3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> Klon"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"<xliff:g id="LABEL">%1$s</xliff:g> Peribadi"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Minta PIN sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Minta corak buka kunci sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Minta kata laluan sebelum menyahsemat"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Kemas kini dalam "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Kemas kini <xliff:g id="TYPE">%1$s</xliff:g> dalam "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Kemas kini <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> dalam "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Kemas kinikan item ini dalam "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dan <xliff:g id="TYPE_2">%3$s</xliff:g> ?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Simpan"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Tidak perlu"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Bukan sekarang"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 924bfe0..394a74e 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"ဒုတိယအလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"တတိယအလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ပင်မဖြုတ်မီမှာ သော့ဖွင့် ရေးဆွဲမှုပုံစံကို မေးကြည့်ရန်"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ပင်မဖြုတ်မီမှာ စကားဝှက်ကို မေးကြည့်ရန်"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"တွင် အပ်ဒိတ်လုပ်လိုပါသလား။"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> ကို "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" တွင် အပ်ဒိတ်လုပ်လိုပါသလား။"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> နှင့် <xliff:g id="TYPE_1">%2$s</xliff:g> ကို "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"တွင် အပ်ဒိတ်လုပ်လိုပါသလား။"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ဤအရာများကို "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" တွင် အပ်ဒိတ်လုပ်မလား- <xliff:g id="TYPE_0">%1$s</xliff:g>၊ <xliff:g id="TYPE_1">%2$s</xliff:g> နှင့် <xliff:g id="TYPE_2">%3$s</xliff:g>။"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"သိမ်းရန်"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"မလိုပါ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ယခုမလုပ်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7ae201c..ffc8bea 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Andre <xliff:g id="LABEL">%1$s</xliff:g> for jobben"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Tredje <xliff:g id="LABEL">%1$s</xliff:g> for jobben"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klon <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Krev PIN-kode for å løsne app"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Krev opplåsingsmønster for å løsne apper"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Krev passord for å løsne apper"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Vil du oppdatere i "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Vil du oppdatere <xliff:g id="TYPE">%1$s</xliff:g> i "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Vil du oppdatere <xliff:g id="TYPE_0">%1$s</xliff:g> og <xliff:g id="TYPE_1">%2$s</xliff:g> i "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Vil du oppdatere disse elementene i "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> og <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Lagre"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nei takk"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ikke nå"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 7d6d09f..672cfbc 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"कार्यालयको दोस्रो <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"कार्यालयको तेस्रो <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> क्लोन गर्नुहोस्"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"अनपिन गर्नुअघि PIN मागियोस्"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन गर्नअघि अनलक प्याटर्न माग्नुहोस्"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" मा अद्यावधिक गर्ने हो?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> लाई "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" मा अद्यावधिक गर्ने हो?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> र <xliff:g id="TYPE_1">%2$s</xliff:g> लाई "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" मा अद्यावधिक गर्ने हो?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"तपाईं "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" मा भएका निम्न वस्तुहरू अपडेट गर्न चाहनुहुन्छ: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> र <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"सेभ गर्नुहोस्"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"पर्दैन, धन्यवाद"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"अहिले होइन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f92b394..2846b6a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2e <xliff:g id="LABEL">%1$s</xliff:g>, werk"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3e <xliff:g id="LABEL">%1$s</xliff:g>, werk"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Kloon van <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Privé <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Vraag pin voor losmaken"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vraag om ontgrendelingspatroon voor losmaken"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vraag wachtwoord voor losmaken"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Updaten in "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> updaten in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> en <xliff:g id="TYPE_1">%2$s</xliff:g> updaten in "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Deze items updaten in "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> en <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Opslaan"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nee, bedankt"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Niet nu"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index b94ab75..41d8b50 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2ୟ କାର୍ଯ୍ୟ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3ୟ କାର୍ଯ୍ୟ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> କ୍ଲୋନ"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ PIN ପଚାରନ୍ତୁ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ ଲକ୍‌ ଖୋଲିବା ପାଟର୍ନ ପଚାରନ୍ତୁ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ ପାସ୍‌ୱର୍ଡ ପଚାରନ୍ତୁ"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"ରେ ଅପ୍‌ଡେଟ୍ କରିବେ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"ରେ <xliff:g id="TYPE">%1$s</xliff:g>କୁ ଅପ୍‌ଡେଟ୍ କରିବେ।"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"ରେ <xliff:g id="TYPE_0">%1$s</xliff:g> ଏବଂ <xliff:g id="TYPE_1">%2$s</xliff:g> ଅପ୍‌ଡେଟ୍ କରିବେ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"ରେ ଏହି ଆଇଟମଗୁଡ଼ିକୁ ଅପଡେଟ କରିବେ: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ଏବଂ <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"ସେଭ୍‌ କରନ୍ତୁ"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ନାଁ, ପଚାରିଥିବାରୁ ଧନ୍ୟବାଦ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ଏବେ ନୁହେଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c17b17b..8b9934f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"ਦੂਸਰੀ ਕਾਰਜ-ਸਥਾਨ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"ਤੀਸਰੀ ਕਾਰਜ-ਸਥਾਨ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> ਦਾ ਕਲੋਨ"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ਅਨਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪਿੰਨ ਮੰਗੋ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ਅਨਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਅਣਲਾਕ ਪੈਟਰਨ ਵਾਸਤੇ ਪੁੱਛੋ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ਅਣਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪਾਸਵਰਡ ਮੰਗੋ"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"ਕੀ ਤੁਸੀਂ "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ਵਿੱਚ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"ਕੀ ਤੁਸੀਂ "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ਵਿੱਚ <xliff:g id="TYPE">%1$s</xliff:g> ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"ਕੀ ਤੁਸੀਂ "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ਵਿੱਚ <xliff:g id="TYPE_0">%1$s</xliff:g> ਅਤੇ <xliff:g id="TYPE_1">%2$s</xliff:g> ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ਕੀ ਤੁਸੀਂ "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ਵਿੱਚ ਇਨ੍ਹਾਂ ਆਈਟਮਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ਅਤੇ<xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"ਰੱਖਿਅਤ ਕਰੋ"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ਹੁਣੇ ਨਹੀਂ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 45353b1..880892f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1869,6 +1869,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> – praca 2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> – praca 3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klon aplikacji <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Podaj PIN, aby odpiąć"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Aby odpiąć, poproś o wzór odblokowania"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Aby odpiąć, poproś o hasło"</string>
@@ -2033,8 +2035,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Zaktualizować w: "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Zaktualizować: <xliff:g id="TYPE">%1$s</xliff:g> w: "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Zaktualizować: <xliff:g id="TYPE_0">%1$s</xliff:g> i <xliff:g id="TYPE_1">%2$s</xliff:g> w: "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Zaktualizować w "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" te elementy: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> i <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Zapisz"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nie, dziękuję"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Nie teraz"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d4f3529..70f80a8 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Segundo <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Terceiro <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> (clone)"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"<xliff:g id="LABEL">%1$s</xliff:g> particular"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pedir PIN antes de liberar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir senha antes de liberar"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Atualizar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Atualizar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Atualizar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Atualizar estes itens em "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salvar"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Agora não"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Agora não"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 53fbfd3..7341500 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2.º <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3.º <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clonar <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> privado"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pedir PIN antes de soltar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de soltar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir palavra-passe antes de soltar"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Quer atualizar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Quer atualizar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Quer atualizar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Atualizar estes itens no serviço "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Guardar"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Não, obrigado"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Agora não"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d4f3529..70f80a8 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Segundo <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Terceiro <xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> (clone)"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"<xliff:g id="LABEL">%1$s</xliff:g> particular"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pedir PIN antes de liberar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir senha antes de liberar"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Atualizar em "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Atualizar <xliff:g id="TYPE">%1$s</xliff:g> em "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Atualizar <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> em "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Atualizar estes itens em "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salvar"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Agora não"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Agora não"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ce0eb91..5dc5463 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -670,14 +670,10 @@
   </string-array>
     <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"A apărut o eroare. Încearcă din nou."</string>
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string>
-    <!-- no translation found for device_unlock_notification_name (2632928999862915709) -->
-    <skip />
-    <!-- no translation found for alternative_unlock_setup_notification_title (6241508547901933544) -->
-    <skip />
-    <!-- no translation found for alternative_face_setup_notification_content (3384959224091897331) -->
-    <skip />
-    <!-- no translation found for alternative_fp_setup_notification_content (7454096947415721639) -->
-    <skip />
+    <string name="device_unlock_notification_name" msgid="2632928999862915709">"Deblocarea dispozitivului"</string>
+    <string name="alternative_unlock_setup_notification_title" msgid="6241508547901933544">"Încearcă o altă modalitate de deblocare"</string>
+    <string name="alternative_face_setup_notification_content" msgid="3384959224091897331">"Folosește Deblocarea facială atunci când amprenta ta nu este recunoscută, de exemplu, când ai degetele ude"</string>
+    <string name="alternative_fp_setup_notification_content" msgid="7454096947415721639">"Folosește Deblocarea cu amprenta atunci când chipul tău nu este recunoscut, de exemplu, când nu există suficientă lumină"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Deblocare facială"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problemă cu Deblocarea facială"</string>
     <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Atinge pentru a șterge modelul facial, apoi adaugă din nou chipul"</string>
@@ -1872,6 +1868,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> pentru serviciu (2)"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> pentru serviciu (3)"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Clonă pentru <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicită codul PIN înainte de a anula fixarea"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicită mai întâi modelul pentru deblocare"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicită parola înainte de a anula fixarea"</string>
@@ -2036,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Actualizezi în "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Actualizezi <xliff:g id="TYPE">%1$s</xliff:g> în "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Actualizezi <xliff:g id="TYPE_0">%1$s</xliff:g> și <xliff:g id="TYPE_1">%2$s</xliff:g> în "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Actualizezi aceste articole în "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> și <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Salvează"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nu, mulțumesc"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Nu acum"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 155f654..e09593e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1869,6 +1869,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Задача 2: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Задача 3: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Клонировать <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Запрашивать PIN-код"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запрашивать графический ключ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запрашивать пароль"</string>
@@ -2033,8 +2035,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Обновить в сервисе "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Обновить данные (<xliff:g id="TYPE">%1$s</xliff:g>) в сервисе "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Обновить данные (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>) в сервисе "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Обновить данные (<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, <xliff:g id="TYPE_2">%3$s</xliff:g>) в сервисе "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Сохранить"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Нет, спасибо"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Не сейчас"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 7485012..99d90be 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2වන වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3වන වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> ක්ලෝන කරන්න"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ගැලවීමට පෙර PIN විමසන්න"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ගැලවීමට පෙර අගුළු අරින රටාව සඳහා අසන්න"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ගැලවීමට පෙර මුරපදය විමසන්න"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" තුළ යාවත්කාලීන කරන්නද?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" තුළ <xliff:g id="TYPE">%1$s</xliff:g> යාවත්කාලීන කරන්නද?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" තුළ <xliff:g id="TYPE_0">%1$s</xliff:g> සහ <xliff:g id="TYPE_1">%2$s</xliff:g> යාවත්කාලීන කරන්නද?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, සහ <xliff:g id="TYPE_2">%3$s</xliff:g> තුළ මෙම අයිතම යාවත්කාලීන කරන්න ද?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"සුරකින්න"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"එපා ස්තූතියි"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"දැන් නොවේ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c06c7cc..a3ca1a6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1869,6 +1869,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. <xliff:g id="LABEL">%1$s</xliff:g> do práce"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klonovať <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pred odopnutím požiadať o číslo PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred uvoľnením požiadať o bezpečnostný vzor"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odopnutím požiadať o heslo"</string>
@@ -2033,8 +2035,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Aktualizovať v službe "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Chcete údaje <xliff:g id="TYPE">%1$s</xliff:g> aktualizovať v službe "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Chcete položky <xliff:g id="TYPE_0">%1$s</xliff:g> a <xliff:g id="TYPE_1">%2$s</xliff:g> aktualizovať v službe "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Chcete tieto položky aktualizovať v službe "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> a <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Uložiť"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nie, vďaka"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Teraz nie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c25e052..5292fc3 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1869,6 +1869,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. službeni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. službeni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klon aplikacije <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Zasebni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Zahtevaj PIN pred odpenjanjem"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odpenjanjem vprašaj za geslo"</string>
@@ -2033,8 +2034,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Želite posodobiti v aplikaciji "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Želite posodobiti element <xliff:g id="TYPE">%1$s</xliff:g> v aplikaciji "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Želite posodobiti elementa <xliff:g id="TYPE_0">%1$s</xliff:g> in <xliff:g id="TYPE_1">%2$s</xliff:g> v aplikaciji "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Želite posodobiti te elemente v "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> in <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Shrani"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ne, hvala"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Ne zdaj"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index c93b699..fd74534 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> i dytë i punës"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> i tretë i punës"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klonim i <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Zhgozhdimi kërkon PIN-in"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Kërko motivin e shkyçjes para heqjes së gozhdimit"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Kërko fjalëkalim para heqjes nga gozhdimi."</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Të përditësohet në "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Të përditësohet <xliff:g id="TYPE">%1$s</xliff:g> në "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Të përditësohet <xliff:g id="TYPE_0">%1$s</xliff:g> dhe <xliff:g id="TYPE_1">%2$s</xliff:g> në "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Të përditësohen këta artikuj në "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dhe <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Ruaj"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Jo, faleminderit"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Jo tani"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 14dfac5..81c1915 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -494,7 +494,7 @@
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Омогућава апликацији да шаље команде SIM картици. То је веома опасно."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"препознавање физичких активности"</string>
     <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ова апликација може да препозна физичке активности."</string>
-    <string name="permlab_camera" msgid="6320282492904119413">"снимање фотографија и видео снимака"</string>
+    <string name="permlab_camera" msgid="6320282492904119413">"снимање фотографија и видеа"</string>
     <string name="permdesc_camera" msgid="5240801376168647151">"Ова апликација може да снима слике и видео снимке помоћу камере док се апликација користи."</string>
     <string name="permlab_backgroundCamera" msgid="7549917926079731681">"да снима слике и видео снимке у позадини"</string>
     <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ова апликација може да снима фотографије и видео снимке помоћу камере у било ком тренутку."</string>
@@ -745,8 +745,8 @@
     <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Омогућава апликацији да чита видео фајлове из дељеног меморијског простора."</string>
     <string name="permlab_readMediaImages" msgid="4057590631020986789">"читање фајлова слика из дељеног меморијског простора"</string>
     <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Омогућава апликацији да чита фајлове слика из дељеног меморијског простора."</string>
-    <string name="permlab_readVisualUserSelect" msgid="5516204215354667586">"читање фајлова слика и видео снимака које корисник бира из дељеног меморијског простора"</string>
-    <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Омогућава апликацији да чита фајлове слика и видео снимака које изаберете из дељеног меморијског простора."</string>
+    <string name="permlab_readVisualUserSelect" msgid="5516204215354667586">"читање фајлова слика и видеа које корисник бира из дељеног меморијског простора"</string>
+    <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Омогућава апликацији да чита фајлове слика и видеа које изаберете из дељеног меморијског простора."</string>
     <string name="permlab_sdcardWrite" msgid="4863021819671416668">"мењање или брисање садржаја дељеног меморијског простора"</string>
     <string name="permdesc_sdcardWrite" msgid="8376047679331387102">"Дозвољава апликацији да уписује садржај дељеног меморијског простора."</string>
     <string name="permlab_use_sip" msgid="8250774565189337477">"упућивање/пријем SIP позива"</string>
@@ -1172,7 +1172,7 @@
     <string name="app_running_notification_text" msgid="5120815883400228566">"Додирните за више информација или заустављање апликације."</string>
     <string name="ok" msgid="2646370155170753815">"Потврди"</string>
     <string name="cancel" msgid="6908697720451760115">"Откажи"</string>
-    <string name="yes" msgid="9069828999585032361">"Потврди"</string>
+    <string name="yes" msgid="9069828999585032361">"У реду"</string>
     <string name="no" msgid="5122037903299899715">"Откажи"</string>
     <string name="dialog_alert_title" msgid="651856561974090712">"Пажња"</string>
     <string name="loading" msgid="3138021523725055037">"Учитава се…"</string>
@@ -1417,7 +1417,7 @@
     <string name="ext_media_new_notification_message" msgid="6095403121990786986">"Додирните да бисте подесили"</string>
     <string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"Изаберите да бисте подесили"</string>
     <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"Можда морате да реформатирате уређај. Додирните да бисте избацили."</string>
-    <string name="ext_media_ready_notification_message" msgid="7509496364380197369">"За чување слика, видео снимака, музике и другог садржаја"</string>
+    <string name="ext_media_ready_notification_message" msgid="7509496364380197369">"За чување слика, видеа, музике и другог садржаја"</string>
     <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"Прегледајте медијске фајлове"</string>
     <string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"Проблем са: <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> не ради"</string>
@@ -1868,6 +1868,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2. пословни <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3. пословни имејл <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Клонирај <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Тражи PIN пре откачињања"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тражи лозинку пре откачињања"</string>
@@ -2032,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Желите ли да ажурирате у услузи "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Желите ли да ажурирате ставку <xliff:g id="TYPE">%1$s</xliff:g> у услузи "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Желите ли да ажурирате ставке <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> у услузи "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Желите ли да ажурирате ове ставке у услузи "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Сачувај"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Не, хвала"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Не сада"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8d0a41f..1ca3e08 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Andra <xliff:g id="LABEL">%1$s</xliff:g> för jobbet"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Tredje <xliff:g id="LABEL">%1$s</xliff:g> för jobbet"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Klona <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Be om pinkod innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Be om upplåsningsmönster innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Be om lösenord innan skärmen slutar fästas"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Vill du uppdatera detta i "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Vill du uppdatera <xliff:g id="TYPE">%1$s</xliff:g> i "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Vill du uppdatera <xliff:g id="TYPE_0">%1$s</xliff:g> och <xliff:g id="TYPE_1">%2$s</xliff:g> i "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Vill du uppdatera dessa objekt i "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> och <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Spara"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Nej tack"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Inte nu"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index afc1fc3..1ec2eef 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> ya 2 ya Kazini"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> ya 3 ya Kazini"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Nakala ya <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Faragha <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Itisha PIN kabla hujabandua"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Omba mchoro wa kufungua kabla hujabandua"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Omba nenosiri kabla hujabandua"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Ungependa kusasisha katika "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Ungependa kusasisha <xliff:g id="TYPE">%1$s</xliff:g> katika "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Ungependa kusasisha <xliff:g id="TYPE_0">%1$s</xliff:g> na <xliff:g id="TYPE_1">%2$s</xliff:g> katika "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Ungependa kusasisha vipengee hivi katika "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> na <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Hifadhi"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Hapana"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Si sasa"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6052b4f..5b2b2b2 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2வது பணி <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3வது பணி <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"குளோன் <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"அகற்றும் முன் PINஐக் கேள்"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"அகற்றும் முன் அன்லாக் பேட்டர்னைக் கேள்"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"அகற்றும் முன் கடவுச்சொல்லைக் கேள்"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" இல் மாற்றவா?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" இல் <xliff:g id="TYPE">%1$s</xliff:g>ஐ மாற்றவா?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273"><b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" இல் <xliff:g id="TYPE_0">%1$s</xliff:g> மற்றும் <xliff:g id="TYPE_1">%2$s</xliff:g>ஐ மாற்றவா?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" இல் <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> மற்றும் <xliff:g id="TYPE_2">%3$s</xliff:g>ஐ மாற்றவா?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"சேமி"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"வேண்டாம்"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"இப்போது வேண்டாம்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9da39c3..5b9e737 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2వ కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3వ కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"క్లోన్ <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ ఆకృతి కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"లో అప్‌డేట్ చేయాలా?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g>ని "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"లో అప్‌డేట్ చేయాలా?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> మరియు <xliff:g id="TYPE_1">%2$s</xliff:g>ని "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"లో అప్‌డేట్ చేయాలా?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ఈ ఐటెమ్‌లను "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"లో అప్‌డేట్ చేయండి: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> అలాగే <xliff:g id="TYPE_2">%3$s</xliff:g> అప్‌డేట్ చేయాలా?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"సేవ్ చేయండి"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"వద్దు, ధన్యవాదాలు"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ఇప్పుడు కాదు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index fa66380..804562a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> งานที่ 2"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> งานที่ 3"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"โคลน <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> ส่วนตัว"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"ขอ PIN ก่อนเลิกปักหมุด"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ขอรูปแบบการปลดล็อกก่อนเลิกปักหมุด"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ขอรหัสผ่านก่อนเลิกปักหมุด"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"อัปเดตใน "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ไหม"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"อัปเดต<xliff:g id="TYPE">%1$s</xliff:g>ใน "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ไหม"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"อัปเดต<xliff:g id="TYPE_0">%1$s</xliff:g>และ<xliff:g id="TYPE_1">%2$s</xliff:g>ใน "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ไหม"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"อัปเดตข้อมูล<xliff:g id="TYPE_0">%1$s</xliff:g> <xliff:g id="TYPE_1">%2$s</xliff:g> และ<xliff:g id="TYPE_2">%3$s</xliff:g>ใน "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ไหม"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"บันทึก"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"ไม่เป็นไร"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ไว้ทีหลัง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 840810c..51e7ec6 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Pangalawang <xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Pangatlong <xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"I-clone ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Pribadong <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Humingi ng PIN bago mag-unpin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Humingi ng password bago mag-unpin"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"I-update sa "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"I-update ang <xliff:g id="TYPE">%1$s</xliff:g> sa "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"I-update ang <xliff:g id="TYPE_0">%1$s</xliff:g> at <xliff:g id="TYPE_1">%2$s</xliff:g> sa "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"I-update ang mga item na ito sa "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, at <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"I-save"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Hindi, salamat na lang"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Hindi ngayon"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 90a5731..33b050a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"İş için 2. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"İş için 3. <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> klonu"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" hizmetinde güncellensin mi?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" hizmetinde güncellensin mi?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> ve <xliff:g id="TYPE_1">%2$s</xliff:g> "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" hizmetinde güncellensin mi?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Şu öğeler "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" hizmetinde güncellensin mi: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> ve <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Kaydet"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Hayır, teşekkürler"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Şimdi değil"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f8a725d..f6d426d 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1869,6 +1869,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-а робота: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-я робота: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Копія додатка <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"PIN-код для відкріплення"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитувати ключ розблокування перед відкріпленням"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитувати пароль перед відкріпленням"</string>
@@ -2033,8 +2035,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Оновити в сервісі "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Оновити дані (<xliff:g id="TYPE">%1$s</xliff:g>) у сервісі "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Оновити дані (<xliff:g id="TYPE_0">%1$s</xliff:g> і <xliff:g id="TYPE_1">%2$s</xliff:g>) у сервісі "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Оновити в сервісі "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" такі дані: <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> і <xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Зберегти"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Ні, дякую"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Не зараз"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 227f25d..c8cd1cb 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"دوسرا کام <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"تیسرا کام <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> کلون"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"‏پن ہٹانے سے پہلے PIN طلب کریں"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" میں اپ ڈیٹ کریں؟"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704"><b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" میں <xliff:g id="TYPE">%1$s</xliff:g> اپ ڈیٹ کریں؟"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> اور <xliff:g id="TYPE_1">%2$s</xliff:g> کو "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" میں اپ ڈیٹ کریں؟"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"ان آئٹمز کو "<b>"<xliff:g id="LABEL">%4$s</xliff:g> "</b>" میں اپ ڈیٹ کریں: <xliff:g id="TYPE_0">%1$s</xliff:g>، <xliff:g id="TYPE_1">%2$s</xliff:g> اور <xliff:g id="TYPE_2">%3$s</xliff:g>؟"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"محفوظ کریں"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"نہیں، شکریہ"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"ابھی نہیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a0b43c7..696edd3 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2-ishxona <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3-ishxona <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<xliff:g id="LABEL">%1$s</xliff:g> nusxasini yaratish"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Shaxsiy <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Yechishda PIN kod talab qilinsin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Yechishdan oldin grafik kalit so‘ralsin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Bo‘shatishdan oldin parol so‘ralsin"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136"><b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" xizmatida yangilansinmi?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"<xliff:g id="TYPE">%1$s</xliff:g> "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" xizmatida yangilansinmi?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"<xliff:g id="TYPE_0">%1$s</xliff:g> va <xliff:g id="TYPE_1">%2$s</xliff:g> "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" xizmatida yangilansinmi?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626"><b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" xizmatidagi <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> va <xliff:g id="TYPE_2">%3$s</xliff:g> yangilansinmi?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Saqlash"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Kerak emas"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Keyinroq"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index f6abefb..5b92609 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1867,6 +1867,8 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Công việc thứ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Công việc thứ 2 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"Sao chép <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <!-- no translation found for private_profile_label_badge (1712086003787839183) -->
+    <skip />
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Hỏi mã PIN trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Hỏi hình mở khóa trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Hỏi mật khẩu trước khi bỏ ghim"</string>
@@ -2031,8 +2033,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Cập nhật trong "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Cập nhật <xliff:g id="TYPE">%1$s</xliff:g> trong "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Cập nhật <xliff:g id="TYPE_0">%1$s</xliff:g> và <xliff:g id="TYPE_1">%2$s</xliff:g> trong "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Cập nhật các mục <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> và <xliff:g id="TYPE_2">%3$s</xliff:g> trong "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Lưu"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Không, cảm ơn"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Để sau"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 10d865b..f900b59 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"第二个工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"第三个工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"<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>”"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"取消时要求输入PIN码"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消时要求绘制解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消时要求输入密码"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"要在"<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"中更新吗?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"要在"<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"中更新<xliff:g id="TYPE">%1$s</xliff:g>吗?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"要在"<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"中更新<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>吗?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"要在"<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"中更新<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>吗?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"保存"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"不用了"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"以后再说"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 8de6931..714053939 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"第二個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"第三個工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"複製 <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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"取消固定時必須輸入 PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須提供解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"要在 "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" 中更新嗎?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"要在 "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" 中更新<xliff:g id="TYPE">%1$s</xliff:g>嗎?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"要在 "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" 中更新<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>嗎?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"要在 "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" 中更新<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>嗎?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"儲存"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"不用了,謝謝"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"暫時不要"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c0631e9..61fe939 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"第 2 項工作:<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"第 3 項工作:<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"複製<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>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"取消固定時必須輸入 PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"要更新 "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" 中的內容嗎?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"要更新 "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" 中的<xliff:g id="TYPE">%1$s</xliff:g>嗎?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"要更新 "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" 中的<xliff:g id="TYPE_0">%1$s</xliff:g>和<xliff:g id="TYPE_1">%2$s</xliff:g>嗎?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"要更新 "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" 中的<xliff:g id="TYPE_0">%1$s</xliff:g>、<xliff:g id="TYPE_1">%2$s</xliff:g>和<xliff:g id="TYPE_2">%3$s</xliff:g>嗎?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"儲存"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"不用了,謝謝"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"暫時不要"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e9b4080..77a41fce 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1867,6 +1867,7 @@
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"Umsebenzi wesibili <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"Umsebenzi wesithathu <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="clone_profile_label_badge" msgid="1871997694718793964">"I-Clone <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="private_profile_label_badge" msgid="1712086003787839183">"Okuyimfihlo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Cela iphinikhodi ngaphambi kokuphina"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Cela iphethini yokuvula ngaphambi kokususa ukuphina"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Cela iphasiwedi ngaphambi kokususa ukuphina"</string>
@@ -2031,8 +2032,7 @@
     <string name="autofill_update_title" msgid="3630695947047069136">"Buyekeza ku-"<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_type" msgid="5264152633488495704">"Buyekeza i-<xliff:g id="TYPE">%1$s</xliff:g> ku-"<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string>
     <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Buyekeza i-<xliff:g id="TYPE_0">%1$s</xliff:g> ne-<xliff:g id="TYPE_1">%2$s</xliff:g> ku-"<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string>
-    <!-- no translation found for autofill_update_title_with_3types (8285767070604652626) -->
-    <skip />
+    <string name="autofill_update_title_with_3types" msgid="8285767070604652626">"Buyekeza lezi zinto ku-"<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g>, ne-<xliff:g id="TYPE_2">%3$s</xliff:g>?"</string>
     <string name="autofill_save_yes" msgid="8035743017382012850">"Londoloza"</string>
     <string name="autofill_save_no" msgid="9212826374207023544">"Cha ngiyabonga"</string>
     <string name="autofill_save_notnow" msgid="2853932672029024195">"Hhayi manje"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f45499a..e54347f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3537,11 +3537,11 @@
         <attr name="preferKeepClear" format="boolean" />
 
         <!-- <p>Whether or not the auto handwriting initiation is enabled in this View.
-             <p>For a view with active {@link android.view.inputmethod.InputConnection},
-             if auto handwriting initiation is enabled stylus movement within its view boundary
+             <p>For a view with an active {@link android.view.inputmethod.InputConnection},
+             if auto handwriting initiation is enabled, stylus movement within its view boundary
              will automatically trigger the handwriting mode.
-             <p>This is true by default.
-             See {@link android.view.View#setAutoHandwritingEnabled}. -->
+             See {@link android.view.View#setAutoHandwritingEnabled}.
+             <p>The default value of this flag is configurable by the device manufacturer. -->
         <attr name="autoHandwritingEnabled" format="boolean" />
 
         <!-- <p>The amount of offset that is applied to the left edge of the view's stylus
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index e67ea82..a6830a6 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -552,10 +552,6 @@
     <color name="accessibility_magnification_thumbnail_container_background_color">#99000000</color>
     <color name="accessibility_magnification_thumbnail_container_stroke_color">#FFFFFF</color>
 
-    <!-- Color of camera light when camera is in use -->
-    <color name="camera_privacy_light_day">#FFFFFF</color>
-    <color name="camera_privacy_light_night">#FFFFFF</color>
-
     <!-- Lily Language Picker language item view colors -->
     <color name="language_picker_item_text_color">#202124</color>
     <color name="language_picker_item_text_color_secondary">#5F6368</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0ea5b8a..367a4f5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -935,6 +935,9 @@
          without impacting power, performance, and app compatibility (e.g. protected content). -->
     <bool name="config_reduceBrightColorsAvailable">@bool/config_setColorTransformAccelerated</bool>
 
+    <!-- Whether to show Fold lock behavior setting feature in Settings App -->
+    <bool name="config_fold_lock_behavior">false</bool>
+
     <string-array name="config_reduceBrightColorsCoefficientsNonlinear">
         <!-- a-coefficient --> <item>-0.4429953456</item>
         <!-- b-coefficient --> <item>-0.2434077725</item>
@@ -1185,6 +1188,9 @@
     -->
     <integer name="config_shortPressOnSleepBehavior">0</integer>
 
+    <!-- Whether to silence telephony ringer on sleep key event -->
+    <bool name="config_silenceRingerOnSleepKey">false</bool>
+
     <!-- Control the behavior when the user long presses the stem primary button.
          Stem primary button is only used on watch form factor. If a device is not
          a watch, setting this config is no-op.
@@ -3487,7 +3493,8 @@
     <!-- Whether this device prefers to show snapshot or splash screen on back predict target.
          When set true, there will create windowless starting surface for the preview target, so it
          won't affect activity's lifecycle. This should only be disabled on low-ram device. -->
-    <bool name="config_predictShowStartingSurface">true</bool>
+    <!-- TODO(b/268563842) enable once activity snapshot is ready -->
+    <bool name="config_predictShowStartingSurface">false</bool>
 
     <!-- default window ShowCircularMask property -->
     <bool name="config_windowShowCircularMask">false</bool>
@@ -5476,6 +5483,13 @@
          of known compatibility issues. -->
     <string-array name="config_highRefreshRateBlacklist"></string-array>
 
+    <!-- The list of packages to automatically opt in to refresh rate suppressing by small area
+    detection. Format of this array should be packageName:threshold and threshold value should
+     be between 0 to 1-->
+    <string-array name="config_smallAreaDetectionAllowlist" translatable="false">
+        <!-- Add packages:threshold here -->
+    </string-array>
+
     <!-- The list of packages to force slowJpegMode for Apps using Camera API1 -->
     <string-array name="config_forceSlowJpegModeList" translatable="false">
         <!-- Add packages here -->
@@ -6181,6 +6195,8 @@
 
     <!-- Default value for Settings.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED -->
     <bool name="config_searchPressHoldNavHandleEnabledDefault">true</bool>
+    <!-- Default value for Settings.ASSIST_LONG_PRESS_HOME_ENABLED for search overlay -->
+    <bool name="config_searchLongPressHomeEnabledDefault">true</bool>
 
     <!-- The maximum byte size of the information contained in the bundle of
     HotwordDetectedResult. -->
@@ -6534,8 +6550,19 @@
 
     <!-- Interval in milliseconds to average light sensor values for camera light brightness -->
     <integer name="config_cameraPrivacyLightAlsAveragingIntervalMillis">3000</integer>
-    <!-- Light sensor's lux value to use as the threshold between using day or night brightness -->
-    <integer name="config_cameraPrivacyLightAlsNightThreshold">4</integer>
+    <!-- Ambient Light sensor's lux values to use as the threshold between brightness colors defined
+         by config_cameraPrivacyLightColors. If the ambient brightness less than the first element
+         in this array then lights of type "camera" will be set to the color in position 0 of
+         config_cameraPrivacyLightColors. This array must be strictly increasing and have a length
+         of zero means there is only one brightness -->
+    <integer-array name="config_cameraPrivacyLightAlsLuxThresholds">
+    </integer-array>
+    <!-- Colors to configure the camera privacy light at different brightnesses. This array must
+         have exactly one more entry than config_cameraPrivacyLightAlsLuxThresholds,
+         or a length of zero if the feature isn't supported. If nonempty and the device doesn't have
+         an ambient light sensor the last element in this array will be the only one used -->
+    <array name="config_cameraPrivacyLightColors">
+    </array>
 
     <!-- List of system components which are allowed to receive ServiceState entries in an
          un-sanitized form, even if the location toggle is off. This is intended ONLY for system
diff --git a/core/res/res/values/config_tv_external_input_logging.xml b/core/res/res/values/config_tv_external_input_logging.xml
new file mode 100644
index 0000000..72e30be
--- /dev/null
+++ b/core/res/res/values/config_tv_external_input_logging.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (C) 2023 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds.  Do not translate.
+
+     NOTE: The naming convention is "config_camelCaseValue". Some legacy
+     entries do not follow the convention, but all new entries should. -->
+
+<resources>
+    <bool name="config_tvExternalInputLoggingDisplayNameFilterEnabled">false</bool>
+
+    <string-array name="config_tvExternalInputLoggingDeviceOnScreenDisplayNames">
+        <item>Chromecast</item>
+        <item>Chromecast HD</item>
+        <item>SHIELD</item>
+        <item>Roku</item>
+        <item>Roku Express 4</item>
+        <item>Home Theater</item>
+        <item>Fire TV Stick</item>
+        <item>PlayStation 5</item>
+        <item>NintendoSwitch</item>
+    </string-array>
+
+    <string-array name="config_tvExternalInputLoggingDeviceBrandNames">
+        <item>Chromecast</item>
+        <item>SHIELD</item>
+        <item>Roku</item>
+        <item>Apple</item>
+        <item>Fire TV</item>
+        <item>PlayStation</item>
+        <item>Nintendo</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 164f713..13d04e5 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1500,12 +1500,8 @@
         <item name="fontFamily">google-sans-text-medium</item>
         <item name="textStyle">normal</item>
         <item name="textAllCaps">false</item>
-        <item name="layout_marginTop">6dp</item>
-        <item name="layout_marginBottom">6dp</item>
-        <item name="paddingStart">16dp</item>
-        <item name="paddingEnd">16dp</item>
-        <item name="paddingTop">8dp</item>
-        <item name="paddingBottom">8dp</item>
+        <item name="paddingStart">24dp</item>
+        <item name="paddingEnd">24dp</item>
     </style>
     <!-- @hide Tonal button for Autofill half screen dialog -->
     <style name="AutofillHalfSheetTonalButton" parent="AutofillHalfSheetButton">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 889901a..1965172 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -343,6 +343,7 @@
   <java-symbol type="string" name="config_defaultHealthConnectApp" />
   <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
   <java-symbol type="bool" name="config_enableScreenshotChord" />
+  <java-symbol type="bool" name="config_fold_lock_behavior" />
   <java-symbol type="bool" name="config_enableWifiDisplay" />
   <java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
   <java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
@@ -464,6 +465,7 @@
   <java-symbol type="integer" name="config_toastDefaultGravity" />
   <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
+  <java-symbol type="bool" name="config_silenceRingerOnSleepKey" />
   <java-symbol type="integer" name="config_longPressOnStemPrimaryBehavior" />
   <java-symbol type="integer" name="config_shortPressOnStemPrimaryBehavior" />
   <java-symbol type="string" name="config_primaryShortPressTargetActivity" />
@@ -4287,6 +4289,8 @@
   <java-symbol type="array" name="config_highRefreshRateBlacklist" />
   <java-symbol type="array" name="config_forceSlowJpegModeList" />
 
+  <java-symbol type="array" name="config_smallAreaDetectionAllowlist" />
+
   <java-symbol type="layout" name="chooser_dialog" />
   <java-symbol type="layout" name="chooser_dialog_item" />
   <java-symbol type="drawable" name="chooser_dialog_background" />
@@ -4914,6 +4918,7 @@
   <java-symbol type="bool" name="config_assistTouchGestureEnabledDefault" />
 
   <java-symbol type="bool" name="config_searchPressHoldNavHandleEnabledDefault" />
+  <java-symbol type="bool" name="config_searchLongPressHomeEnabledDefault" />
 
   <java-symbol type="integer" name="config_hotwordDetectedResultMaxBundleSize" />
 
@@ -5009,10 +5014,9 @@
   <java-symbol type="string" name="vdm_camera_access_denied" />
   <java-symbol type="string" name="vdm_secure_window" />
 
-  <java-symbol type="color" name="camera_privacy_light_day"/>
-  <java-symbol type="color" name="camera_privacy_light_night"/>
   <java-symbol type="integer" name="config_cameraPrivacyLightAlsAveragingIntervalMillis"/>
-  <java-symbol type="integer" name="config_cameraPrivacyLightAlsNightThreshold"/>
+  <java-symbol type="array" name="config_cameraPrivacyLightAlsLuxThresholds"/>
+  <java-symbol type="array" name="config_cameraPrivacyLightColors"/>
 
   <java-symbol type="bool" name="config_bg_current_drain_monitor_enabled" />
   <java-symbol type="array" name="config_bg_current_drain_threshold_to_restricted_bucket" />
@@ -5221,4 +5225,9 @@
 
   <!-- Whether we order unlocking and waking -->
   <java-symbol type="bool" name="config_orderUnlockAndWake" />
+
+  <!-- External TV Input Logging Configs -->
+  <java-symbol type="bool" name="config_tvExternalInputLoggingDisplayNameFilterEnabled" />
+  <java-symbol type="array" name="config_tvExternalInputLoggingDeviceOnScreenDisplayNames" />
+  <java-symbol type="array" name="config_tvExternalInputLoggingDeviceBrandNames" />
 </resources>
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index 0676f89..aaaa3c7 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -241,7 +241,8 @@
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(new String[]{"CustomConsumer1", "CustomConsumer2"},
                         /* includePowerModels */ true,
-                        /* includeProcessStats */true)
+                        /* includeProcessStats */ true,
+                        /* minConsumedPowerThreshold */ 0)
                         .setDischargePercentage(20)
                         .setDischargedPowerRange(1000, 2000)
                         .setDischargeDurationMs(1234)
@@ -325,7 +326,7 @@
     @Test
     public void testLargeAtomTruncated() {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[0], true, false);
+                new BatteryUsageStats.Builder(new String[0], true, false, 0);
         // If not truncated, this BatteryUsageStats object would generate a proto buffer
         // significantly larger than 50 Kb
         for (int i = 0; i < 3000; i++) {
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index a358c4f..20d8d91 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -86,8 +86,8 @@
     <uses-permission android:name="android.permission.TEST_GRANTED" />
     <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
     <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
-    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
-    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" android:maxSdkVersion="34"/>
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" android:maxSdkVersion="34"/>
 
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
diff --git a/core/tests/coretests/res/layout/viewgroup_test.xml b/core/tests/coretests/res/layout/viewgroup_test.xml
index 04f4f52..9b57047 100644
--- a/core/tests/coretests/res/layout/viewgroup_test.xml
+++ b/core/tests/coretests/res/layout/viewgroup_test.xml
@@ -42,8 +42,8 @@
         android:id="@+id/view_translate"
         android:layout_width="20dp"
         android:layout_height="10dp"
-        android:translationX="10dp"
-        android:translationY="20dp"
+        android:translationX="10px"
+        android:translationY="20px"
         android:text="Hello World!"
         android:background="#2F00FF00" />
     <FrameLayout
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a923479..0778311 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -67,7 +67,6 @@
 import android.window.WindowContextInfo;
 import android.window.WindowTokenClientController;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
@@ -254,15 +253,9 @@
 
             // Execute a local relaunch item with current scaled config (e.g. simulate recreate),
             // the config should not be scaled again.
-            final Configuration currentConfig = activity.getResources().getConfiguration();
-            final ClientTransaction localTransaction =
-                    newTransaction(activityThread, activity.getActivityToken());
-            localTransaction.addCallback(ActivityRelaunchItem.obtain(
-                    null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
-                    new MergedConfiguration(currentConfig, currentConfig),
-                    true /* preserveWindow */));
             InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                    () -> activityThread.executeTransaction(localTransaction));
+                    () -> activityThread.executeTransaction(
+                            newRelaunchResumeTransaction(activity)));
 
             assertScreenScale(scale, activity, originalActivityConfig, originalActivityMetrics);
         } finally {
@@ -630,7 +623,6 @@
         });
     }
 
-    @FlakyTest(bugId = 295234586)
     @Test
     public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
@@ -836,8 +828,10 @@
     }
 
     private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
+        final Configuration currentConfig = activity.getResources().getConfiguration();
         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
-                null, 0, new MergedConfiguration(), false /* preserveWindow */);
+                null, 0, new MergedConfiguration(currentConfig, currentConfig),
+                false /* preserveWindow */);
         final ResumeActivityItem resumeStateRequest =
                 ResumeActivityItem.obtain(true /* isForward */,
                         false /* shouldSendCompatFakeFocus*/);
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 1ea20f1..349fe7b 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -53,6 +53,7 @@
     private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec
     private static final String DEFAULT_VALUE = "test_default_value";
     private static final String NAMESPACE = "namespace1";
+    private static final String NAMESPACE2 = "namespace2";
     private static final String KEY = "key1";
     private static final String KEY2 = "key2";
     private static final String KEY3 = "key3";
@@ -67,6 +68,89 @@
         deleteViaContentProvider(NAMESPACE, KEY);
         deleteViaContentProvider(NAMESPACE, KEY2);
         deleteViaContentProvider(NAMESPACE, KEY3);
+        DeviceConfig.clearAllLocalOverrides();
+    }
+
+    /**
+     * Test that creating a sticky local override for a flag prevents further writes to that flag.
+     */
+    @Test
+    public void testAddStickyLocalOverridePreventsWrites() {
+        DeviceConfig.setLocalOverride(NAMESPACE, KEY, VALUE);
+
+        String key1Value = DeviceConfig.getProperty(NAMESPACE, KEY);
+        assertThat(key1Value).isEqualTo(VALUE);
+
+        DeviceConfig.setProperty(NAMESPACE, KEY, VALUE2, /* makeDefault= */ false);
+        key1Value = DeviceConfig.getProperty(NAMESPACE, KEY);
+        assertThat(key1Value).isEqualTo(VALUE);
+    }
+
+    /**
+     * Test that when we locally override a flag, we can still write other flags.
+     */
+    @Test
+    public void testAddStickyLocalOverrideDoesNotAffectOtherFlags() {
+        DeviceConfig.setLocalOverride(NAMESPACE, KEY, VALUE);
+        DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, /* makeDefault= */ false);
+        String key2Value = DeviceConfig.getProperty(NAMESPACE, KEY2);
+        assertThat(key2Value).isEqualTo(VALUE2);
+    }
+
+    /**
+     * Test that when we apply some overrides, they show up in the override list.
+     */
+    @Test
+    public void testGetStickyLocalOverrides() {
+        DeviceConfig.setProperty(NAMESPACE, KEY, VALUE2, false);
+        DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE, false);
+        DeviceConfig.setLocalOverride(NAMESPACE, KEY, VALUE);
+        DeviceConfig.setLocalOverride(NAMESPACE, KEY2, VALUE2);
+
+        Map<String, Map<String, String>> expectedOverrides = new HashMap<>();
+        Map<String, String> expectedInnerMap = new HashMap<>();
+        expectedInnerMap.put(KEY, VALUE2);
+        expectedInnerMap.put(KEY2, VALUE);
+        expectedOverrides.put(NAMESPACE, expectedInnerMap);
+
+        assertThat(DeviceConfig.getUnderlyingValuesForOverriddenFlags())
+                .isEqualTo(expectedOverrides);
+    }
+
+    /**
+     * Test that when we clear all overrides, the override list is empty.
+     */
+    @Test
+    public void testClearStickyLocalOverrides() {
+        DeviceConfig.setLocalOverride(NAMESPACE2, KEY, VALUE);
+        DeviceConfig.setLocalOverride(NAMESPACE2, KEY2, VALUE2);
+
+        DeviceConfig.clearAllLocalOverrides();
+
+        Map<String, Map<String, String>> overrides =
+                DeviceConfig.getUnderlyingValuesForOverriddenFlags();
+        assertThat(overrides).isEmpty();
+    }
+
+    /**
+     * Test that when we clear a single override, it doesn't appear in the list.
+     */
+    @Test
+    public void testClearStickyLocalOverride() {
+        DeviceConfig.setProperty(NAMESPACE, KEY, VALUE2, false);
+        DeviceConfig.setProperty(NAMESPACE2, KEY2, VALUE, false);
+        DeviceConfig.setLocalOverride(NAMESPACE, KEY, VALUE);
+        DeviceConfig.setLocalOverride(NAMESPACE2, KEY2, VALUE2);
+
+        DeviceConfig.clearLocalOverride(NAMESPACE, KEY);
+
+        Map<String, Map<String, String>> expectedOverrides = new HashMap<>();
+        Map<String, String> expectedInnerMap = new HashMap<>();
+        expectedInnerMap.put(KEY2, VALUE);
+        expectedOverrides.put(NAMESPACE2, expectedInnerMap);
+
+        assertThat(DeviceConfig.getUnderlyingValuesForOverriddenFlags())
+                .isEqualTo(expectedOverrides);
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/provider/NameValueCacheTest.java b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
index 54a3817..87e4a42 100644
--- a/core/tests/coretests/src/android/provider/NameValueCacheTest.java
+++ b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
@@ -39,6 +39,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -54,6 +55,7 @@
  * Due to how the classes are structured, we have to test it in a somewhat roundabout way. We're
  * mocking out the contentProvider and are handcrafting very specific Bundles to answer the queries.
  */
+@Ignore("b/297724333")
 @Presubmit
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -233,6 +235,7 @@
         mConfigsCacheGenerationStore.close();
     }
 
+    @Ignore("b/297724333")
     @Test
     public void testCaching_singleNamespace() throws Exception {
         HashMap<String, String> keyValues = new HashMap<>();
@@ -270,6 +273,7 @@
         assertThat(cachedKeyValues2).containsExactlyEntriesIn(keyValues);
     }
 
+    @Ignore("b/297724333")
     @Test
     public void testCaching_multipleNamespaces() throws Exception {
         HashMap<String, String> keyValues = new HashMap<>();
@@ -309,6 +313,7 @@
         assertThat(cachedKeyValues2).containsExactlyEntriesIn(keyValues2);
     }
 
+    @Ignore("b/297724333")
     @Test
     public void testCaching_emptyNamespace() throws Exception {
         Map<String, String> returnedValues = Settings.Config.getStrings(mMockContentResolver,
@@ -325,6 +330,7 @@
         assertThat(cachedKeyValues).isEmpty();
     }
 
+    @Ignore("b/297724333")
     @Test
     public void testCaching_singleSetting() throws Exception {
         Settings.Secure.putString(mMockContentResolver, SETTING, "a");
@@ -355,6 +361,7 @@
         assertThat(cachedValue2).isEqualTo("b");
     }
 
+    @Ignore("b/297724333")
     @Test
     public void testCaching_multipleSettings() throws Exception {
         Settings.Secure.putString(mMockContentResolver, SETTING, "a");
@@ -385,6 +392,7 @@
         assertThat(cachedValue2).isEqualTo("b");
     }
 
+    @Ignore("b/297724333")
     @Test
     public void testCaching_unsetSetting() throws Exception {
         String returnedValue = Settings.Secure.getString(mMockContentResolver, SETTING);
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index f45db23..8c93fbb 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -81,8 +81,7 @@
                     Insets.of(10, 10, 10, 10), rect, rect, rect, rect));
             mController.calculateInsets(
                     false,
-                    false,
-                    TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                    TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                     SOFT_INPUT_ADJUST_RESIZE, 0, 0);
             mImeConsumer = mController.getImeSourceConsumer();
         });
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index b8f0d5c..1568174 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -16,7 +16,7 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
 import static android.view.InsetsController.ANIMATION_TYPE_NONE;
 import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
@@ -171,8 +171,7 @@
             mController.onStateChanged(state);
             mController.calculateInsets(
                     false,
-                    false,
-                    TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                    TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                     SOFT_INPUT_ADJUST_RESIZE, 0, 0);
             mController.onFrameChanged(new Rect(0, 0, 100, 100));
         });
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index b06cd39..906d84e 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -16,8 +16,9 @@
 
 package android.view;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.InsetsSource.FLAG_FORCE_CONSUMING;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.InsetsState.ISIDE_BOTTOM;
 import static android.view.InsetsState.ISIDE_TOP;
@@ -101,7 +102,7 @@
                 .setVisible(true);
         SparseIntArray typeSideMap = new SparseIntArray();
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 typeSideMap);
         assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
@@ -120,7 +121,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 null);
         assertEquals(100, insets.getStableInsetBottom());
         assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(systemBars()));
@@ -139,7 +140,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -154,7 +155,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -169,7 +170,7 @@
                 .setFrame(new Rect(0, 200, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
         assertEquals(100, insets.getInsets(ime()).bottom);
@@ -185,12 +186,12 @@
                 .setFrame(new Rect(0, 200, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
+                ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
-        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
+        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
                 SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, null);
+                ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
     }
 
@@ -200,12 +201,12 @@
                 .setFrame(new Rect(0, 0, 100, 100))
                 .setVisible(false);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
-                TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
+                TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
-        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
+        insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
                 SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, null);
+                ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
     }
 
@@ -213,22 +214,23 @@
     public void testCalculateInsets_flagLayoutNoLimits() {
         mState.getOrCreateSource(ID_STATUS_BAR, statusBars())
                 .setFrame(new Rect(0, 0, 100, 100))
-                .setVisible(true);
+                .setVisible(true)
+                .setFlags(FLAG_FORCE_CONSUMING);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetTop());
         insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
         insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_WALLPAPER, WINDOWING_MODE_UNDEFINED, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_WALLPAPER, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
         insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
-                0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_FREEFORM, null);
+                SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+                0 /* legacySystemUiFlags */, TYPE_APPLICATION, ACTIVITY_TYPE_STANDARD, null);
         assertEquals(100, insets.getSystemWindowInsetTop());
     }
 
@@ -243,7 +245,7 @@
                 .setVisible(true);
 
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 400), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 400), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
@@ -255,7 +257,7 @@
                 .setVisible(true);
 
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 150, 400), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 150, 400), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
     }
@@ -269,7 +271,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -284,7 +286,7 @@
                 .setFrame(new Rect(80, 0, 100, 300))
                 .setVisible(true);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
-                false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+                0, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
         assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
         assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -292,11 +294,11 @@
 
     @Test
     public void testCalculateInsets_emptyIme() {
-        WindowInsets insets1 = mState.calculateInsets(new Rect(), null, false, false,
-                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+        WindowInsets insets1 = mState.calculateInsets(new Rect(), null, false,
+                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         mState.getOrCreateSource(ID_IME, ime());
-        WindowInsets insets2 = mState.calculateInsets(new Rect(), null, false, false,
-                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+        WindowInsets insets2 = mState.calculateInsets(new Rect(), null, false,
+                SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(Insets.NONE, insets1.getInsets(ime()));
         assertEquals(Insets.NONE, insets2.getInsets(ime()));
         assertEquals(insets1, insets2);
@@ -311,8 +313,8 @@
                 .setFrame(new Rect(0, 200, 100, 300))
                 .setVisible(true);
         mState.removeSource(ID_IME);
-        WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
-                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+        WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+                SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED, null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
     }
 
@@ -527,7 +529,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_PAN, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 100, 0, 100), visibleInsets);
     }
@@ -546,7 +548,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_NOTHING, 0 /* windowFlags */);
         assertEquals(Insets.of(0, 100, 0, 0), visibleInsets);
     }
@@ -565,7 +567,7 @@
                 .setFrame(new Rect(0, 100, 100, 300))
                 .setVisible(true);
         Insets visibleInsets = mState.calculateVisibleInsets(
-                new Rect(0, 0, 100, 300), TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+                new Rect(0, 0, 100, 300), TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 SOFT_INPUT_ADJUST_PAN, FLAG_LAYOUT_NO_LIMITS);
         assertEquals(Insets.NONE, visibleInsets);
     }
@@ -599,8 +601,8 @@
                 new Rect(0, 0, 1, 2),
                 new Rect(197, 296, 200, 300),
                 new Rect(197, 296, 200, 300)));
-        DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false, false,
-                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+        DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false,
+                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION, ACTIVITY_TYPE_UNDEFINED,
                 new SparseIntArray()).getDisplayCutout();
         assertEquals(0, cutout.getSafeInsetLeft());
         assertEquals(1, cutout.getSafeInsetTop());
@@ -625,8 +627,8 @@
                 new RoundedCorner(POSITION_BOTTOM_RIGHT, 20, 180, 380),
                 new RoundedCorner(POSITION_BOTTOM_LEFT, 20, 20, 380)));
         WindowInsets windowInsets = mState.calculateInsets(new Rect(1, 2, 197, 396), null, false,
-                false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+                ACTIVITY_TYPE_UNDEFINED, new SparseIntArray());
         assertEquals(new RoundedCorner(POSITION_TOP_LEFT, 10, 9, 8),
                 windowInsets.getRoundedCorner(POSITION_TOP_LEFT));
         assertEquals(new RoundedCorner(POSITION_TOP_RIGHT, 10, 189, 8),
@@ -642,8 +644,8 @@
         mState.setDisplayFrame(new Rect(0, 0, 200, 400));
         mState.setDisplayShape(DisplayShape.createDefaultDisplayShape(200, 400, false));
         WindowInsets windowInsets = mState.calculateInsets(new Rect(10, 20, 200, 400), null, false,
-                false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
-                WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+                SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+                ACTIVITY_TYPE_UNDEFINED, new SparseIntArray());
 
         final DisplayShape expect =
                 DisplayShape.createDefaultDisplayShape(200, 400, false).setOffset(-10, -20);
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index bd309b9..2afbb47 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -38,17 +38,12 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
 
 import android.app.Instrumentation;
-import android.app.UiModeManager;
 import android.content.Context;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Binder;
-import android.os.SystemProperties;
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
-import android.util.Log;
 import android.view.WindowInsets.Side;
 import android.view.WindowInsets.Type;
 
@@ -57,9 +52,6 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.ShellIdentityUtils;
-
-import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -79,7 +71,6 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ViewRootImplTest {
-    private static final String TAG = "ViewRootImplTest";
 
     private ViewRootImpl mViewRootImpl;
     private volatile boolean mKeyReceived = false;
@@ -110,18 +101,6 @@
                 mViewRootImpl = new ViewRootImpl(sContext, sContext.getDisplayNoVerify()));
     }
 
-    @After
-    public void teardown() {
-        ShellIdentityUtils.invokeWithShellPermissions(() -> {
-            Settings.Secure.resetToDefaults(sContext.getContentResolver(), TAG);
-
-            var uiModeManager = sContext.getSystemService(UiModeManager.class);
-            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
-
-            setForceDarkSysProp(false);
-        });
-    }
-
     @Test
     public void adjustLayoutParamsForCompatibility_layoutFullscreen() {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
@@ -421,96 +400,6 @@
         assertThat(result).isFalse();
     }
 
-    @Test
-    public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
-        ShellIdentityUtils.invokeWithShellPermissions(() -> {
-            Settings.Secure.putInt(
-                    sContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
-                    /* value= */ 0
-            );
-            var uiModeManager = sContext.getSystemService(UiModeManager.class);
-            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
-        });
-
-        sInstrumentation.runOnMainSync(() ->
-                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
-        );
-
-        assertThat(mViewRootImpl.isForceDarkEnabled()).isFalse();
-    }
-
-    @Test
-    public void forceInvertOnDarkThemeOff_forceDarkModeEnabled() {
-        ShellIdentityUtils.invokeWithShellPermissions(() -> {
-            Settings.Secure.putInt(
-                    sContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
-                    /* value= */ 1
-            );
-            var uiModeManager = sContext.getSystemService(UiModeManager.class);
-            uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
-        });
-
-        sInstrumentation.runOnMainSync(() ->
-                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
-        );
-
-        assertThat(mViewRootImpl.isForceDarkEnabled()).isTrue();
-    }
-
-    @Test
-    public void forceInvertOffForceDarkOff_forceDarkModeDisabled() {
-        ShellIdentityUtils.invokeWithShellPermissions(() -> {
-            Settings.Secure.putInt(
-                    sContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
-                    /* value= */ 0
-            );
-
-            // TODO(b/297556388): figure out how to set this without getting blocked by SELinux
-            assumeTrue(setForceDarkSysProp(true));
-        });
-
-        sInstrumentation.runOnMainSync(() ->
-                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
-        );
-
-        assertThat(mViewRootImpl.isForceDarkEnabled()).isFalse();
-    }
-
-    @Test
-    public void forceInvertOffForceDarkOn_forceDarkModeEnabled() {
-        ShellIdentityUtils.invokeWithShellPermissions(() -> {
-            Settings.Secure.putInt(
-                    sContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED,
-                    /* value= */ 0
-            );
-
-            assumeTrue(setForceDarkSysProp(true));
-        });
-
-        sInstrumentation.runOnMainSync(() ->
-                mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())
-        );
-
-        assertThat(mViewRootImpl.isForceDarkEnabled()).isTrue();
-    }
-
-    private boolean setForceDarkSysProp(boolean isForceDarkEnabled) {
-        try {
-            SystemProperties.set(
-                    ThreadedRenderer.DEBUG_FORCE_DARK,
-                    Boolean.toString(isForceDarkEnabled)
-            );
-            return true;
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to set force_dark sysprop", e);
-            return false;
-        }
-    }
-
     class KeyView extends View {
         KeyView(Context context) {
             super(context);
diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
index 6189914..fe30d81 100644
--- a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.app.procstats;
 
-import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
-
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
@@ -108,7 +106,8 @@
         ProcessState processState =
                 processStats.getProcessStateLocked(
                         APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
-        processState.setCombinedState(STATE_TOP, NOW_MS);
+        processState.setState(ActivityManager.PROCESS_STATE_TOP, ProcessStats.ADJ_MEM_FACTOR_NORMAL,
+                NOW_MS, /* pkgList */ null);
         processState.commitStateTime(NOW_MS + TimeUnit.SECONDS.toMillis(DURATION_SECS));
         processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
         verify(mStatsEventOutput)
@@ -158,6 +157,38 @@
     }
 
     @SmallTest
+    public void testDumpFrozenDuration() throws Exception {
+        ProcessStats processStats = new ProcessStats();
+        ProcessState processState =
+                processStats.getProcessStateLocked(
+                        APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME);
+        processState.setState(ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+                ProcessStats.ADJ_MEM_FACTOR_NORMAL, NOW_MS, /* pkgList */ null);
+        processState.onProcessFrozen(NOW_MS   + 1 * TimeUnit.SECONDS.toMillis(DURATION_SECS),
+            /* pkgList */ null);
+        processState.onProcessUnfrozen(NOW_MS + 2 * TimeUnit.SECONDS.toMillis(DURATION_SECS),
+            /* pkgList */ null);
+        processState.commitStateTime(NOW_MS   + 3 * TimeUnit.SECONDS.toMillis(DURATION_SECS));
+        processStats.dumpProcessState(FrameworkStatsLog.PROCESS_STATE, mStatsEventOutput);
+        verify(mStatsEventOutput)
+                .write(
+                        eq(FrameworkStatsLog.PROCESS_STATE),
+                        eq(APP_1_UID),
+                        eq(APP_1_PROCESS_NAME),
+                        anyInt(),
+                        anyInt(),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(0),
+                        eq(2 * DURATION_SECS),  // bound_fgs
+                        eq(0),
+                        eq(0),
+                        eq(DURATION_SECS),  // frozen
+                        eq(0));
+    }
+
+    @SmallTest
     public void testDumpProcessAssociation() throws Exception {
         ProcessStats processStats = new ProcessStats();
         AssociationState associationState =
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index 246a1e7..a0e9947 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -48,7 +48,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -102,6 +104,25 @@
         return partitionOrder.toString();
     }
 
+    // configIndex should come from real time partition order cause partitions could get
+    // reordered by /product/overlay/partition_order.xml
+    private Map<String, Integer> createConfigIndexes(OverlayConfig overlayConfig,
+            String... configPartitions) {
+        Map<String, Integer> configIndexes = new HashMap<>();
+        for (int i = 0; i < configPartitions.length; i++) {
+            configIndexes.put(configPartitions[i], -1);
+        }
+
+        String[] partitions = overlayConfig.getPartitionOrder().split(", ");
+        int index = 0;
+        for (int i = 0; i < partitions.length; i++) {
+            if (configIndexes.containsKey(partitions[i])) {
+                configIndexes.put(partitions[i], index++);
+            }
+        }
+        return configIndexes;
+    }
+
     @Test
     public void testImmutableAfterNonImmutableFails() throws IOException {
         mExpectedException.expect(IllegalStateException.class);
@@ -292,11 +313,13 @@
         mScannerRule.addOverlay(createFile("/system_ext/overlay/five.apk"), "five");
 
         final OverlayConfig overlayConfig = createConfigImpl();
-        assertConfig(overlayConfig, "one", true, true, 0);
-        assertConfig(overlayConfig, "two", true, true, 1);
-        assertConfig(overlayConfig, "three", true, true, 2);
-        assertConfig(overlayConfig, "four", true, true, 3);
-        assertConfig(overlayConfig, "five", true, true, 4);
+        Map<String, Integer> configIndexes = createConfigIndexes(overlayConfig,
+                "vendor", "odm", "oem", "product", "system_ext");
+        assertConfig(overlayConfig, "one", true, true, configIndexes.get("vendor"));
+        assertConfig(overlayConfig, "two", true, true, configIndexes.get("odm"));
+        assertConfig(overlayConfig, "three", true, true, configIndexes.get("oem"));
+        assertConfig(overlayConfig, "four", true, true, configIndexes.get("product"));
+        assertConfig(overlayConfig, "five", true, true, configIndexes.get("system_ext"));
     }
 
     @Test
@@ -313,9 +336,11 @@
                 true, 0);
 
         final OverlayConfig overlayConfig = createConfigImpl();
-        assertConfig(overlayConfig, "one", false, true, 0);
-        assertConfig(overlayConfig, "two", true, true, 1);
-        assertConfig(overlayConfig, "three", false, true, 2);
+        Map<String, Integer> configIndexes = createConfigIndexes(overlayConfig,
+                "vendor", "odm", "product");
+        assertConfig(overlayConfig, "one", false, true, configIndexes.get("vendor"));
+        assertConfig(overlayConfig, "two", true, true, configIndexes.get("odm"));
+        assertConfig(overlayConfig, "three", false, true, configIndexes.get("product"));
     }
 
     @Test
@@ -327,9 +352,11 @@
                 true, 0);
 
         final OverlayConfig overlayConfig = createConfigImpl();
-        assertConfig(overlayConfig, "one", false, true, 0);
-        assertConfig(overlayConfig, "two", false, true, 1);
-        assertConfig(overlayConfig, "three", false, true, 2);
+        Map<String, Integer> configIndexes = createConfigIndexes(overlayConfig,
+                "vendor", "odm", "product");
+        assertConfig(overlayConfig, "one", false, true, configIndexes.get("vendor"));
+        assertConfig(overlayConfig, "two", false, true, configIndexes.get("odm"));
+        assertConfig(overlayConfig, "three", false, true, configIndexes.get("product"));
     }
 
     @Test
diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java
index 274c25a..94298dc 100644
--- a/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/persistence/ParsedVibrationTest.java
@@ -92,18 +92,18 @@
     }
 
     @Test
-    public void testGetVibrationEffectListForTesting() {
+    public void testGetVibrationEffects() {
         ParsedVibration parsedVibration =
                 new ParsedVibration(List.of(mEffect1, mEffect2, mEffect3));
-        assertThat(parsedVibration.getVibrationEffectListForTesting())
+        assertThat(parsedVibration.getVibrationEffects())
                 .containsExactly(mEffect1, mEffect2, mEffect3)
                 .inOrder();
 
         parsedVibration = new ParsedVibration(List.of(mEffect1));
-        assertThat(parsedVibration.getVibrationEffectListForTesting()).containsExactly(mEffect1);
+        assertThat(parsedVibration.getVibrationEffects()).containsExactly(mEffect1);
 
         parsedVibration = new ParsedVibration(List.of());
-        assertThat(parsedVibration.getVibrationEffectListForTesting()).isEmpty();
+        assertThat(parsedVibration.getVibrationEffects()).isEmpty();
     }
 
     private Subject assertThatResolution(
diff --git a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
index d73b5cb..2814a5f 100644
--- a/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
+++ b/core/tests/vibrator/src/android/os/vibrator/persistence/VibrationEffectXmlSerializationTest.java
@@ -363,8 +363,7 @@
 
     private void assertParseDocumentSucceeds(String xml, int flags, VibrationEffect... effects)
             throws Exception {
-        assertThat(parseDocument(xml, flags).getVibrationEffectListForTesting())
-                .containsExactly(effects);
+        assertThat(parseDocument(xml, flags).getVibrationEffects()).containsExactly(effects);
     }
 
     /**
@@ -381,8 +380,7 @@
         String tagName = parser.getName();
         assertThat(Set.of("vibration", "vibration-select")).contains(tagName);
 
-        assertThat(parseElement(parser, flags).getVibrationEffectListForTesting())
-                .containsExactly(effects);
+        assertThat(parseElement(parser, flags).getVibrationEffects()).containsExactly(effects);
         assertThat(parser.getEventType()).isEqualTo(XmlPullParser.END_TAG);
         assertThat(parser.getName()).isEqualTo(tagName);
     }
diff --git a/data/keyboards/Vendor_18d1_Product_9451.idc b/data/keyboards/Vendor_18d1_Product_9451.idc
index e13fcb2..07cfc79 100644
--- a/data/keyboards/Vendor_18d1_Product_9451.idc
+++ b/data/keyboards/Vendor_18d1_Product_9451.idc
@@ -13,11 +13,10 @@
 # limitations under the License.
 
 #
-# Input Device Configuration file for a flavor of the Google Reference RCU Remote.
+# Input Device Configuration file for a flavor of Google Remote Control.
 #
 #
 
 # Basic Parameters
-keyboard.layout = Vendor_0957_Product_0001
 keyboard.doNotWakeByDefault = 1
-audio.mic = 1
\ No newline at end of file
+audio.mic = 1
diff --git a/data/keyboards/Vendor_18d1_Product_9451.kl b/data/keyboards/Vendor_18d1_Product_9451.kl
new file mode 100644
index 0000000..fb425be
--- /dev/null
+++ b/data/keyboards/Vendor_18d1_Product_9451.kl
@@ -0,0 +1,39 @@
+# Copyright 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Key Layout file for flavor of Google Remote Control.
+#
+
+key 116   POWER         WAKE
+key 217   ASSIST        WAKE
+
+key 103   DPAD_UP
+key 108   DPAD_DOWN
+key 105   DPAD_LEFT
+key 106   DPAD_RIGHT
+key 353   DPAD_CENTER
+
+key 158   BACK
+key 172   HOME          WAKE
+
+key 113   VOLUME_MUTE
+key 114   VOLUME_DOWN
+key 115   VOLUME_UP
+
+# custom keys
+key usage 0x000c0186    MACRO_1      WAKE
+
+key usage 0x000c0077    BUTTON_3     WAKE #YouTube
+key usage 0x000c0078    BUTTON_4     WAKE #Netflix
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index e2bb6a6..14d5eaf 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -167,8 +167,8 @@
     jint uniqueId = event.getUniqueId();
     jint type = event.getType();
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    jstring message = env->NewStringUTF(event.getMessage().string());
-    ALOGV("JNIOnInfoListener::onInfo => %d | %d | %s", uniqueId, type, event.getMessage().string());
+    jstring message = env->NewStringUTF(event.getMessage().c_str());
+    ALOGV("JNIOnInfoListener::onInfo => %d | %d | %s", uniqueId, type, event.getMessage().c_str());
 
     env->CallStaticVoidMethod(
             mClass,
@@ -273,15 +273,15 @@
                 const char* value = pConstraints->getAsByteArray(&key);
                 if (NULL != value) {
                     ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(strlen(value)));
-                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
+                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.c_str()));
                     env->SetByteArrayRegion(dataArray.get(), 0, strlen(value), (jbyte*)value);
                     env->CallVoidMethod(constraints, ContentValues_putByteArray,
                                         keyString.get(), dataArray.get());
                 }
             } else {
                 String8 value = pConstraints->get(key);
-                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
-                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
+                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.c_str()));
+                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.c_str()));
                 env->CallVoidMethod(constraints, ContentValues_putString,
                                     keyString.get(), valueString.get());
             }
@@ -320,8 +320,8 @@
                     // insert the entry<constraintKey, constraintValue>
                     // to newly created java object
                     String8 value = pMetadata->get(key);
-                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
-                    ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
+                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.c_str()));
+                    ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.c_str()));
                     env->CallVoidMethod(metadata, ContentValues_putString,
                                         keyString.get(), valueString.get());
                 }
@@ -357,19 +357,19 @@
 
         env->CallVoidMethod(
             drmSupportInfo, env->GetMethodID(clazz, "setDescription", "(Ljava/lang/String;)V"),
-            env->NewStringUTF(info.getDescription().string()));
+            env->NewStringUTF(info.getDescription().c_str()));
 
         DrmSupportInfo::MimeTypeIterator iterator = info.getMimeTypeIterator();
         while (iterator.hasNext()) {
             String8  value = iterator.next();
-            env->CallVoidMethod(drmSupportInfo, addMimeTypeId, env->NewStringUTF(value.string()));
+            env->CallVoidMethod(drmSupportInfo, addMimeTypeId, env->NewStringUTF(value.c_str()));
         }
 
         DrmSupportInfo::FileSuffixIterator it = info.getFileSuffixIterator();
         while (it.hasNext()) {
             String8 value = it.next();
             env->CallVoidMethod(
-                drmSupportInfo, addFileSuffixId, env->NewStringUTF(value.string()));
+                drmSupportInfo, addFileSuffixId, env->NewStringUTF(value.c_str()));
         }
 
         env->SetObjectArrayElement(array, i, drmSupportInfo);
@@ -459,7 +459,7 @@
 
         String8 keyString = Utility::getStringValue(env, key.get());
         String8 valueString = Utility::getStringValue(env, valString.get());
-        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
+        ALOGV("Key: %s | Value: %s", keyString.c_str(), valueString.c_str());
 
         drmInfo.put(keyString, valueString);
     }
@@ -488,15 +488,15 @@
         jmethodID constructorId
             = env->GetMethodID(clazz, "<init>", "([BLjava/lang/String;Ljava/lang/String;)V");
         jobject processedData = env->NewObject(clazz, constructorId, dataArray,
-                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::ACCOUNT_ID)).string()),
-                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::SUBSCRIPTION_ID)).string()));
+                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::ACCOUNT_ID)).c_str()),
+                    env->NewStringUTF((drmInfo.get(DrmInfoRequest::SUBSCRIPTION_ID)).c_str()));
 
         constructorId
             = env->GetMethodID(localRef,
                 "<init>", "(IILandroid/drm/ProcessedData;Ljava/lang/String;)V");
 
         drmInfoStatus = env->NewObject(localRef, constructorId, statusCode, infoType,
-                processedData, env->NewStringUTF(pDrmInfoStatus->mimeType.string()));
+                processedData, env->NewStringUTF(pDrmInfoStatus->mimeType.c_str()));
     }
 
     delete[] mData; mData = NULL;
@@ -533,7 +533,7 @@
 
         String8 keyString = Utility::getStringValue(env, key.get());
         String8 valueString = Utility::getStringValue(env, value.get());
-        ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
+        ALOGV("Key: %s | Value: %s", keyString.c_str(), valueString.c_str());
 
         drmInfoReq.put(keyString, valueString);
     }
@@ -554,7 +554,7 @@
             drmInfoObject
                 = env->NewObject(localRef,
                     env->GetMethodID(localRef, "<init>", "(I[BLjava/lang/String;)V"),
-                    mInfoType, dataArray, env->NewStringUTF(pDrmInfo->getMimeType().string()));
+                    mInfoType, dataArray, env->NewStringUTF(pDrmInfo->getMimeType().c_str()));
 
             DrmInfo::KeyIterator it = pDrmInfo->keyIterator();
             jmethodID putMethodId
@@ -563,8 +563,8 @@
             while (it.hasNext()) {
                 String8 key = it.next();
                 String8 value = pDrmInfo->get(key);
-                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
-                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
+                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.c_str()));
+                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.c_str()));
                 env->CallVoidMethod(drmInfoObject, putMethodId,
                     keyString.get(), valueString.get());
             }
@@ -602,7 +602,7 @@
             ->getOriginalMimeType(uniqueId,
                                   Utility::getStringValue(env, path), fd);
     ALOGV("getOriginalMimeType Exit");
-    return env->NewStringUTF(mimeType.string());
+    return env->NewStringUTF(mimeType.c_str());
 }
 
 static jint android_drm_DrmManagerClient_checkRightsStatus(
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 9fb627f..4c4e8fa 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1475,7 +1475,10 @@
         String locale = SystemProperties.get("persist.sys.locale", "en-US");
         String script = ULocale.addLikelySubtags(ULocale.forLanguageTag(locale)).getScript();
 
-        FontConfig config = SystemFonts.getSystemPreinstalledFontConfig();
+        // The feature flag cannot be referred from Zygote. Use legacy fonts.xml for preloading font
+        // files.
+        // TODO(nona): Use new XML file once the feature is fully launched.
+        FontConfig config = SystemFonts.getSystemPreinstalledFontConfigFromLegacyXml();
         for (int i = 0; i < config.getFontFamilies().size(); ++i) {
             FontConfig.FontFamily family = config.getFontFamilies().get(i);
             if (!family.getLocaleList().isEmpty()) {
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 36bfb98..9810022 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -48,6 +48,8 @@
     private static final String TAG = "SystemFonts";
 
     private static final String FONTS_XML = "/system/etc/font_fallback.xml";
+    private static final String LEGACY_FONTS_XML = "/system/etc/fonts.xml";
+
     /** @hide */
     public static final String SYSTEM_FONT_DIR = "/system/fonts/";
     private static final String OEM_XML = "/product/etc/fonts_customization.xml";
@@ -230,7 +232,13 @@
             long lastModifiedDate,
             int configVersion
     ) {
-        return getSystemFontConfigInternal(FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR,
+        final String fontsXml;
+        if (com.android.text.flags.Flags.deprecateFontsXml()) {
+            fontsXml = FONTS_XML;
+        } else {
+            fontsXml = LEGACY_FONTS_XML;
+        }
+        return getSystemFontConfigInternal(fontsXml, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR,
                 updatableFontMap, lastModifiedDate, configVersion);
     }
 
@@ -255,10 +263,24 @@
      * @hide
      */
     public static @NonNull FontConfig getSystemPreinstalledFontConfig() {
-        return getSystemFontConfigInternal(FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR, null,
+        final String fontsXml;
+        if (com.android.text.flags.Flags.deprecateFontsXml()) {
+            fontsXml = FONTS_XML;
+        } else {
+            fontsXml = LEGACY_FONTS_XML;
+        }
+        return getSystemFontConfigInternal(fontsXml, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR, null,
                 0, 0);
     }
 
+    /**
+     * @hide
+     */
+    public static @NonNull FontConfig getSystemPreinstalledFontConfigFromLegacyXml() {
+        return getSystemFontConfigInternal(LEGACY_FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR,
+                null, 0, 0);
+    }
+
     /* package */ static @NonNull FontConfig getSystemFontConfigInternal(
             @NonNull String fontsXml,
             @NonNull String systemFontDir,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 55eabb0..c3d8f9a 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -16,12 +16,14 @@
 
 package androidx.window.extensions;
 
+import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.Context;
 import android.window.TaskFragmentOrganizer;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
 import androidx.window.common.RawFoldingFeatureProducer;
 import androidx.window.extensions.area.WindowAreaComponent;
@@ -111,9 +113,13 @@
      * {@link WindowExtensions#getWindowLayoutComponent()}.
      * @return {@link ActivityEmbeddingComponent} OEM implementation.
      */
-    @NonNull
+    @Nullable
     public ActivityEmbeddingComponent getActivityEmbeddingComponent() {
         if (mSplitController == null) {
+            if (!ActivityTaskManager.supportsMultiWindow(getApplication())) {
+                // Disable AE for device that doesn't support multi window.
+                return null;
+            }
             synchronized (mLock) {
                 if (mSplitController == null) {
                     mSplitController = new SplitController(
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 896fe61..d894487 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -651,7 +651,8 @@
         if (minDimensionsPair == null) {
             return splitAttributes;
         }
-        final FoldingFeature foldingFeature = getFoldingFeature(taskProperties);
+        final FoldingFeature foldingFeature = getFoldingFeatureForHingeType(
+                taskProperties, splitAttributes);
         final Configuration taskConfiguration = taskProperties.getConfiguration();
         final Rect primaryBounds = getPrimaryBounds(taskConfiguration, splitAttributes,
                 foldingFeature);
@@ -726,7 +727,8 @@
     Rect getRelBoundsForPosition(@Position int position, @NonNull TaskProperties taskProperties,
             @NonNull SplitAttributes splitAttributes) {
         final Configuration taskConfiguration = taskProperties.getConfiguration();
-        final FoldingFeature foldingFeature = getFoldingFeature(taskProperties);
+        final FoldingFeature foldingFeature = getFoldingFeatureForHingeType(
+                taskProperties, splitAttributes);
         if (!shouldShowSplit(splitAttributes)) {
             return new Rect();
         }
@@ -933,6 +935,17 @@
     }
 
     @Nullable
+    private FoldingFeature getFoldingFeatureForHingeType(
+            @NonNull TaskProperties taskProperties,
+            @NonNull SplitAttributes splitAttributes) {
+        SplitType splitType = splitAttributes.getSplitType();
+        if (!(splitType instanceof HingeSplitType)) {
+            return null;
+        }
+        return getFoldingFeature(taskProperties);
+    }
+
+    @Nullable
     @VisibleForTesting
     FoldingFeature getFoldingFeature(@NonNull TaskProperties taskProperties) {
         final int displayId = taskProperties.getDisplayId();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index ccf9552..e03e1ec 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -319,13 +319,17 @@
             return features;
         }
 
+        // We will transform the feature bounds to the Activity window, so using the rotation
+        // from the same source (WindowConfiguration) to make sure they are synchronized.
+        final int rotation = windowConfiguration.getDisplayRotation();
+
         for (CommonFoldingFeature baseFeature : storedFeatures) {
             Integer state = convertToExtensionState(baseFeature.getState());
             if (state == null) {
                 continue;
             }
             Rect featureRect = baseFeature.getRect();
-            rotateRectToDisplayRotation(displayId, featureRect);
+            rotateRectToDisplayRotation(displayId, rotation, featureRect);
             transformToWindowSpaceRect(windowConfiguration, featureRect);
 
             if (isZero(featureRect)) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index 5bfb0ebd..15a329bd 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -120,10 +120,12 @@
         }
 
         List<SidecarDisplayFeature> features = new ArrayList<>();
+        final int rotation = activity.getResources().getConfiguration().windowConfiguration
+                .getDisplayRotation();
         for (CommonFoldingFeature baseFeature : mStoredFeatures) {
             SidecarDisplayFeature feature = new SidecarDisplayFeature();
             Rect featureRect = baseFeature.getRect();
-            rotateRectToDisplayRotation(displayId, featureRect);
+            rotateRectToDisplayRotation(displayId, rotation, featureRect);
             transformToWindowSpaceRect(activity, featureRect);
             feature.setRect(featureRect);
             feature.setType(baseFeature.getType());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
index 9e2611f..6b193fc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
@@ -16,8 +16,6 @@
 
 package androidx.window.util;
 
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
@@ -25,12 +23,14 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
+import android.util.RotationUtils;
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.WindowManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.UiContext;
+import androidx.annotation.VisibleForTesting;
 
 /**
  * Util class for both Sidecar and Extensions.
@@ -44,47 +44,41 @@
     /**
      * Rotates the input rectangle specified in default display orientation to the current display
      * rotation.
+     *
+     * @param displayId the display id.
+     * @param rotation the target rotation relative to the default display orientation.
+     * @param inOutRect the input/output Rect as specified in the default display orientation.
      */
-    public static void rotateRectToDisplayRotation(int displayId, Rect inOutRect) {
-        DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
-        DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
-        int rotation = displayInfo.rotation;
+    public static void rotateRectToDisplayRotation(
+            int displayId, @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
+        final DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+        final DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
 
-        boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
-        int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
-        int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
-
-        inOutRect.intersect(0, 0, displayWidth, displayHeight);
-
-        rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
+        rotateRectToDisplayRotation(displayInfo, rotation, inOutRect);
     }
 
-    /**
-     * Rotates the input rectangle within parent bounds for a given delta.
-     */
-    private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
-            @Surface.Rotation int delta) {
-        int origLeft = inOutRect.left;
-        switch (delta) {
-            case ROTATION_0:
-                return;
-            case ROTATION_90:
-                inOutRect.left = inOutRect.top;
-                inOutRect.top = parentWidth - inOutRect.right;
-                inOutRect.right = inOutRect.bottom;
-                inOutRect.bottom = parentWidth - origLeft;
-                return;
-            case ROTATION_180:
-                inOutRect.left = parentWidth - inOutRect.right;
-                inOutRect.right = parentWidth - origLeft;
-                return;
-            case ROTATION_270:
-                inOutRect.left = parentHeight - inOutRect.bottom;
-                inOutRect.bottom = inOutRect.right;
-                inOutRect.right = parentHeight - inOutRect.top;
-                inOutRect.top = origLeft;
-                return;
+    @VisibleForTesting
+    static void rotateRectToDisplayRotation(@NonNull DisplayInfo displayInfo,
+            @Surface.Rotation int rotation, @NonNull Rect inOutRect) {
+        // The inOutRect is specified in the default display orientation, so here we need to get
+        // the display width and height in the default orientation to perform the intersection and
+        // rotation.
+        final boolean isSideRotation =
+                displayInfo.rotation == ROTATION_90 || displayInfo.rotation == ROTATION_270;
+        final int baseDisplayWidth =
+                isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+        final int baseDisplayHeight =
+                isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+
+        final boolean success = inOutRect.intersect(0, 0, baseDisplayWidth, baseDisplayHeight);
+        if (!success) {
+            throw new IllegalArgumentException("inOutRect must intersect with the display."
+                    + " inOutRect: " + inOutRect
+                    + ", baseDisplayWidth: " + baseDisplayWidth
+                    + ", baseDisplayHeight: " + baseDisplayHeight);
         }
+
+        RotationUtils.rotateBounds(inOutRect, baseDisplayWidth, baseDisplayHeight, rotation);
     }
 
     /** Transforms rectangle from absolute coordinate space to the window coordinate space. */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index d189ae2..0682692 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -16,8 +16,11 @@
 
 package androidx.window.extensions;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.ActivityTaskManager;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -29,7 +32,7 @@
 import org.junit.runner.RunWith;
 
 /**
- * Test class for {@link WindowExtensionsTest}.
+ * Test class for {@link WindowExtensions}.
  *
  * Build/Install/Run:
  *  atest WMJetpackUnitTests:WindowExtensionsTest
@@ -52,7 +55,11 @@
 
     @Test
     public void testGetActivityEmbeddingComponent() {
-        assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull();
+        if (ActivityTaskManager.supportsMultiWindow(getInstrumentation().getContext())) {
+            assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull();
+        } else {
+            assertThat(mExtensions.getActivityEmbeddingComponent()).isNull();
+        }
     }
 
     @Test
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java
new file mode 100644
index 0000000..ae783de
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/util/ExtensionHelperTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link ExtensionHelper}.
+ *
+ * Build/Install/Run:
+ *  atest WMJetpackUnitTests:ExtensionHelperTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ExtensionHelperTest {
+
+    private static final int MOCK_DISPLAY_HEIGHT = 1000;
+    private static final int MOCK_DISPLAY_WIDTH = 2000;
+    private static final int MOCK_FEATURE_LEFT = 100;
+    private static final int MOCK_FEATURE_RIGHT = 200;
+
+    private static final int[] ROTATIONS = {
+            Surface.ROTATION_0,
+            Surface.ROTATION_90,
+            Surface.ROTATION_180,
+            Surface.ROTATION_270
+    };
+
+    private static final DisplayInfo[] MOCK_DISPLAY_INFOS = {
+            getMockDisplayInfo(Surface.ROTATION_0),
+            getMockDisplayInfo(Surface.ROTATION_90),
+            getMockDisplayInfo(Surface.ROTATION_180),
+            getMockDisplayInfo(Surface.ROTATION_270),
+    };
+
+    @Test
+    public void testRotateRectToDisplayRotation() {
+        for (int rotation : ROTATIONS) {
+            final Rect expectedResult = getExpectedFeatureRectAfterRotation(rotation);
+            // The method should return correctly rotated Rect even if the requested rotation value
+            // differs from the rotation in DisplayInfo. This is because the WindowConfiguration is
+            // not always synced with DisplayInfo.
+            for (DisplayInfo displayInfo : MOCK_DISPLAY_INFOS) {
+                final Rect rect = getMockFeatureRect();
+                ExtensionHelper.rotateRectToDisplayRotation(displayInfo, rotation, rect);
+                assertEquals(
+                        "Result Rect should equal to expected for rotation: " + rotation
+                                + "; displayInfo: " + displayInfo,
+                        expectedResult, rect);
+            }
+        }
+    }
+
+    @Test
+    public void testRotateRectToDisplayRotation_invalidInputRect() {
+        final Rect invalidRect = new Rect(
+                MOCK_DISPLAY_WIDTH + 10, 0, MOCK_DISPLAY_WIDTH + 10, MOCK_DISPLAY_HEIGHT);
+        assertThrows(IllegalArgumentException.class,
+                () -> ExtensionHelper.rotateRectToDisplayRotation(
+                        MOCK_DISPLAY_INFOS[0], ROTATIONS[0], invalidRect));
+    }
+
+
+    @NonNull
+    private static DisplayInfo getMockDisplayInfo(@Surface.Rotation int rotation) {
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.rotation = rotation;
+        if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
+            displayInfo.logicalWidth = MOCK_DISPLAY_WIDTH;
+            displayInfo.logicalHeight = MOCK_DISPLAY_HEIGHT;
+        } else {
+            displayInfo.logicalWidth = MOCK_DISPLAY_HEIGHT;
+            displayInfo.logicalHeight = MOCK_DISPLAY_WIDTH;
+        }
+        return displayInfo;
+    }
+
+    @NonNull
+    private static Rect getMockFeatureRect() {
+        return new Rect(MOCK_FEATURE_LEFT, 0, MOCK_FEATURE_RIGHT, MOCK_DISPLAY_HEIGHT);
+    }
+
+    @NonNull
+    private static Rect getExpectedFeatureRectAfterRotation(@Surface.Rotation int rotation) {
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                return new Rect(
+                        MOCK_FEATURE_LEFT, 0, MOCK_FEATURE_RIGHT, MOCK_DISPLAY_HEIGHT);
+            case Surface.ROTATION_90:
+                return new Rect(0, MOCK_DISPLAY_WIDTH - MOCK_FEATURE_RIGHT,
+                        MOCK_DISPLAY_HEIGHT, MOCK_DISPLAY_WIDTH - MOCK_FEATURE_LEFT);
+            case Surface.ROTATION_180:
+                return new Rect(MOCK_DISPLAY_WIDTH - MOCK_FEATURE_RIGHT, 0,
+                        MOCK_DISPLAY_WIDTH - MOCK_FEATURE_LEFT, MOCK_DISPLAY_HEIGHT);
+            case Surface.ROTATION_270:
+                return new Rect(0, MOCK_FEATURE_LEFT, MOCK_DISPLAY_HEIGHT,
+                        MOCK_FEATURE_RIGHT);
+            default:
+                throw new IllegalArgumentException("Unknown rotation value: " + rotation);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 1164d37..4f76342 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Het dit"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen onlangse borrels nie"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Beheer borrels enige tyd"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tik hier om te bestuur watter apps en gesprekke in borrels kan verskyn"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Borrel"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Bestuur"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Borrel is toegemaak."</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index ffed367..1e5f5f1 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ገባኝ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ምንም የቅርብ ጊዜ አረፋዎች የሉም"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"የቅርብ ጊዜ አረፋዎች እና የተሰናበቱ አረፋዎች እዚህ ብቅ ይላሉ"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"በማንኛውም ጊዜ ዓረፋዎችን ይቆጣጠሩ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"የትኛዎቹ መተግበሪያዎች እና ውይይቶች ዓረፋ መፍጠር እንደሚችሉ ለማስተዳደር እዚህ ጋር መታ ያድርጉ"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"አረፋ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ያቀናብሩ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"አረፋ ተሰናብቷል።"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 4e9b76b..9c52608 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"حسنًا"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ليس هناك فقاعات محادثات"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"التحكّم في إظهار الفقاعات في أي وقت"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"انقر هنا للتحكّم في إظهار فقاعات التطبيقات والمحادثات التي تريدها."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"فقاعة"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"إدارة"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"تم إغلاق الفقاعة."</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index a583f34..e880b87 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"বুজি পালোঁ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"কোনো শেহতীয়া bubbles নাই"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"যিকোনো সময়তে বাবল নিয়ন্ত্ৰণ কৰক"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"কোনবোৰ এপ্‌ আৰু বাৰ্তালাপ বাবল হ’ব পাৰে সেয়া পৰিচালনা কৰিবলৈ ইয়াত টিপক"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"পৰিচালনা কৰক"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index fb09258..6e746fb 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Anladım"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Yumrucuqlar yoxdur"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Yumrucuqları idarə edin"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Bura toxunaraq yumrucuq göstərəcək tətbiq və söhbətləri idarə edin"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Qabarcıq"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"İdarə edin"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Qabarcıqdan imtina edilib."</string>
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 a9ba12e..3be3269 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Važi"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolišite oblačiće u svakom trenutku"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovde i odredite koje aplikacije i konverzacije mogu da imaju oblačić"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljajte"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index eef363b..85ae1c1 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Зразумела"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Кіруйце наладамі ўсплывальных апавяшчэнняў у любы час"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Каб кіраваць усплывальнымі апавяшчэннямі для праграм і размоў, націсніце тут"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Усплывальнае апавяшчэнне"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 281bd9d..640fb2e 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Разбрах"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма скорошни балончета"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Скорошните и отхвърлените балончета ще се показват тук"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Управление на балончетата по всяко време"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Докоснете тук, за да управл. кои прил. и разговори могат да показват балончета"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управление"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отхвърлено."</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 3dae948..e7c8886 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"বুঝেছি"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"কোনও সাম্প্রতিক বাবল নেই"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"যেকোনও সময় বাবল নিয়ন্ত্রণ করুন"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"কোন অ্যাপ ও কথোপকথনের জন্য বাবলের সুবিধা চান তা ম্যানেজ করতে এখানে ট্যাপ করুন"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ম্যানেজ করুন"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল বাতিল করা হয়েছে।"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 8b7eb61..1335f8d 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Razumijem"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Upravljajte oblačićima u svakom trenutku"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovdje da upravljate time koje aplikacije i razgovori mogu imati oblačić"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljaj"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 2250f9d..22fc21c 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entesos"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hi ha bombolles recents"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bombolles recents i les ignorades es mostraran aquí"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controla les bombolles en qualsevol moment"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toca aquí per gestionar quines aplicacions i converses poden fer servir bombolles"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bombolla"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestiona"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"La bombolla s\'ha ignorat."</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index ebee2c1..a85fa7c 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Žádné nedávné bubliny"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Nastavení bublin můžete kdykoli upravit"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Klepnutím sem lze spravovat, které aplikace a konverzace mohou vytvářet bubliny"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 4e46243..cd621f8 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ingen seneste bobler"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nye bobler og afviste bobler vises her"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Administrer bobler når som helst"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tryk her for at administrere, hvilke apps og samtaler der kan vises i bobler"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen blev lukket."</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 1d5182a..366fdef 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Keine kürzlich geschlossenen Bubbles"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bubble-Einstellungen festlegen"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tippe hier, um zu verwalten, welche Apps und Unterhaltungen als Bubble angezeigt werden können"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Verwalten"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble verworfen."</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 34a6a07..a449b9f 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Το κατάλαβα"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Πατήστε εδώ για τη διαχείριση εφαρμογών και συζητήσεων που προβάλλουν συννεφάκια"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Συννεφάκι"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Διαχείριση"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Το συννεφάκι παραβλέφθηκε."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index c6e1c5f..c7dd388 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles at any time"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index e536930..99da073 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Got it"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles anytime"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index c6e1c5f..c7dd388 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles at any time"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index c6e1c5f..c7dd388 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles at any time"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 83631eb..cc19579 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎Got it‎‏‎‎‏‎"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎No recent bubbles‎‏‎‎‏‎"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎Recent bubbles and dismissed bubbles will appear here‎‏‎‎‏‎"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎Control bubbles anytime‎‏‎‎‏‎"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‎Tap here to manage which apps and conversations can bubble‎‏‎‎‏‎"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎Bubble‎‏‎‎‏‎"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎Manage‎‏‎‎‏‎"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎Bubble dismissed.‎‏‎‎‏‎"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index c0dfeef..80d10f2 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hay burbujas recientes"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controla las burbujas"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Presiona para administrar las apps y conversaciones que pueden mostrar burbujas"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Cuadro"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Se descartó el cuadro."</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 0e66c9b..13dfce0 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hay burbujas recientes"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controla las burbujas cuando quieras"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toca aquí para gestionar qué aplicaciones y conversaciones pueden usar burbujas"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 201f336..269968f 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Selge"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hiljutisi mulle pole"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Siin kuvatakse hiljutised ja suletud mullid."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Juhtige mulle igal ajal"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Puudutage siin, et hallata, milliseid rakendusi ja vestlusi saab mullina kuvada"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Mull"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Halda"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Mullist loobuti."</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 8443954..b4a8d57a 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ados"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ez dago azkenaldiko burbuilarik"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolatu burbuilak edonoiz"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Sakatu hau burbuiletan zein aplikazio eta elkarrizketa ager daitezkeen kudeatzeko"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbuila"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Kudeatu"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Baztertu da globoa."</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 4f546e7..434bfe1 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"متوجه‌ام"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"هیچ حبابک جدیدی وجود ندارد"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابک‌های اخیر و حبابک‌های ردشده اینجا ظاهر خواهند شد"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"کنترل حبابک‌ها در هرزمانی"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"برای مدیریت اینکه کدام برنامه‌ها و مکالمه‌ها حباب داشته باشند، ضربه بزنید"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"حباب"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index d8a18a0..a04ef12 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Okei"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ei viimeaikaisia kuplia"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Muuta kuplien asetuksia milloin tahansa"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Valitse napauttamalla tästä, mitkä sovellukset ja keskustelut voivat kuplia"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Kupla"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Ylläpidä"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Kupla ohitettu."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index b2077f9..fbc6191 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Gérez les bulles en tout temps"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Touchez ici pour gérer les applis et les conversations à inclure aux bulles"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle ignorée."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index b1b8313..e1fe291 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et ignorées s\'afficheront ici"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Contrôlez les bulles à tout moment"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Appuyez ici pour gérer les applis et conversations s\'affichant dans des bulles"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index fd90e31..485a895 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Non hai burbullas recentes"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"As burbullas recentes e ignoradas aparecerán aquí."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controlar as burbullas"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toca para xestionar as aplicacións e conversas que poden aparecer en burbullas"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbulla"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Xestionar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ignorouse a burbulla."</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index d7e34fb..365faef 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"સમજાઈ ગયું"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"તાજેતરના કોઈ બબલ નથી"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"બબલને કોઈપણ સમયે નિયંત્રિત કરે છે"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"કઈ ઍપ અને વાતચીતોને બબલ કરવા માગો છો તે મેનેજ કરવા માટે, અહીં ટૅપ કરો"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"બબલ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"મેનેજ કરો"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"બબલ છોડી દેવાયો."</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 679ea65..76579d1 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -76,19 +76,14 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ठीक है"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के कोई बबल्स नहीं हैं"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"जब चाहें, बबल्स की सुविधा को कंट्रोल करें"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"किसी ऐप्लिकेशन और बातचीत के लिए बबल की सुविधा को मैनेज करने के लिए यहां टैप करें"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"मैनेज करें"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
-    <!-- no translation found for restart_button_description (4564728020654658478) -->
-    <skip />
-    <!-- no translation found for user_aspect_ratio_settings_button_hint (734835849600713016) -->
-    <skip />
-    <!-- no translation found for user_aspect_ratio_settings_button_description (4315566801697411684) -->
-    <skip />
+    <string name="restart_button_description" msgid="4564728020654658478">"बेहतर व्यू पाने के लिए, टैप करके ऐप्लिकेशन को रीस्टार्ट करें"</string>
+    <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"सेटिंग में जाकर इस ऐप्लिकेशन का आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
+    <string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string>
     <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>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 88aa1b2..de071f1 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Shvaćam"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovdje će se prikazivati nedavni i odbačeni oblačići"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Upravljanje oblačićima u svakom trenutku"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovdje da biste odredili koje aplikacije i razgovori mogu imati oblačić"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić odbačen."</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 5a88bc4..b5631bb 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Értem"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nincsenek buborékok a közelmúltból"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Buborékok vezérlése bármikor"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ide koppintva jeleníthetők meg az alkalmazások és a beszélgetések buborékként"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Buborék"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Kezelés"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Buborék elvetve."</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 54b1213..2d5d371 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Եղավ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ամպիկներ չկան"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ամպիկների կարգավորումներ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Հպեք այստեղ՝ ընտրելու, թե որ հավելվածների և զրույցների համար ամպիկներ ցուցադրել"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Պղպջակ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 32167b3..90b1f15 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Oke"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Tidak ada balon baru-baru ini"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Balon yang baru dipakai dan balon yang telah ditutup akan muncul di sini"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrol balon kapan saja"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ketuk di sini untuk mengelola balon aplikasi dan percakapan"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Kelola"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon ditutup."</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 1304ae1..813f9e6 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ég skil"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Engar nýlegar blöðrur"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Hægt er að stjórna blöðrum hvenær sem er"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ýttu hér til að stjórna því hvaða forrit og samtöl mega nota blöðrur."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Blaðra"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Stjórna"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Blöðru lokað."</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index dceac5c..8918821 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nessuna bolla recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Le bolle recenti e ignorate appariranno qui"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Gestisci le bolle in qualsiasi momento"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tocca qui per gestire le app e le conversazioni per cui mostrare le bolle"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Fumetto"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestisci"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Fumetto ignorato."</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 7cde568..4d7a093 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"הבנתי"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"אין בועות מהזמן האחרון"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"שליטה בבועות בכל זמן"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"אפשר להקיש כאן כדי לקבוע אילו אפליקציות ושיחות יוכלו להופיע בבועות"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"בועה"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 3b3c4e4..9668359 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近閉じたバブルはありません"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"バブルはいつでも管理可能"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"バブルで表示するアプリや会話を管理するには、ここをタップします"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"バブル"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 3c32e0e..a949a18 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"გასაგებია"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"აქ გამოჩნდება ბოლოდროინდელი ბუშტები და უარყოფილი ბუშტები"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ამოხტომის გაკონტროლება ნებისმიერ დროს"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"აქ შეეხეთ იმის სამართავად, თუ რომელი აპები და საუბრები ამოხტეს"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ბუშტი"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"მართვა"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ბუშტი დაიხურა."</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index ac5f4bf..cbc9249 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Түсінікті"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Жақындағы қалқыма хабарлар жоқ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Қалқыма хабарларды кез келген уақытта басқарыңыз"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Қалқыма хабарда көрсетілетін қолданбалар мен әңгімелерді реттеу үшін осы жерді түртіңіз."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Көпіршік"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқыма хабар жабылды."</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index adb229a..3e36113 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"យល់ហើយ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"មិនមាន​ពពុះ​ថ្មីៗ​ទេ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ពពុះថ្មីៗ​ និង​ពពុះដែលបានបិទ​​នឹង​បង្ហាញ​នៅទីនេះ"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"គ្រប់គ្រង​ផ្ទាំងអណ្ដែតនៅពេលណាក៏បាន"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ចុចត្រង់នេះ ដើម្បីគ្រប់គ្រងកម្មវិធី និងការសន្ទនាដែលអាចបង្ហាញជាផ្ទាំងអណ្ដែត"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ពពុះ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"គ្រប់គ្រង"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"បានច្រានចោល​សារលេចឡើង។"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 33c50e7..5e0dad8 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ಅರ್ಥವಾಯಿತು"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಬಬಲ್ಸ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ಯಾವ ಆ್ಯಪ್‌ಗಳು ಮತ್ತು ಸಂಭಾಷಣೆಗಳನ್ನು ಬಬಲ್ ಮಾಡಬಹುದು ಎಂಬುದನ್ನು ನಿರ್ವಹಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ಬಬಲ್"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ನಿರ್ವಹಿಸಿ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index dc76769..f1b3455 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"확인"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"최근 대화창 없음"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"언제든지 대화창을 제어하세요"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"대화창을 만들 수 있는 앱과 대화를 관리하려면 여기를 탭하세요."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index b1c0a67..200359a 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Түшүндүм"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Азырынча эч нерсе жок"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Калкып чыкма билдирме түрүндө көрүнө турган колдонмолор менен маектерди тандоо үчүн бул жерди таптаңыз"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Көбүк"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Башкаруу"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Калкып чыкма билдирме жабылды."</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 0b5da77..43835d5 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ເຂົ້າໃຈແລ້ວ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ຄວບຄຸມຟອງໄດ້ທຸກເວລາ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ແຕະບ່ອນນີ້ເພື່ອຈັດການແອັບ ແລະ ການສົນທະນາທີ່ສາມາດສະແດງເປັນແບບຟອງໄດ້"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ຟອງ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ຈັດການ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index ecec41a..0c6cc58 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Supratau"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nėra naujausių burbulų"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Naujausi ir atsisakyti burbulai bus rodomi čia"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bet kada valdyti burbulus"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Palietę čia valdykite, kurie pokalbiai ir programos gali būti rodomi burbuluose"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Debesėlis"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Tvarkyti"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Debesėlio atsisakyta."</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index d3a15bd..f86e937e 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Labi"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nav nesen aizvērtu burbuļu"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Pārvaldīt burbuļus jebkurā laikā"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Pieskarieties šeit, lai pārvaldītu, kuras lietotnes un sarunas var rādīt burbulī"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Burbulis"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Pārvaldīt"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbulis ir noraidīts."</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 008cff2..49e850f 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Сфатив"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нема неодамнешни балончиња"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Неодамнешните и отфрлените балончиња ќе се појавуваат тука"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Контролирајте ги балончињата во секое време"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Допрете тука за да одредите на кои апл. и разговори може да се појават балончиња"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 4e2f339..fbb5514 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"മനസ്സിലായി"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ബബിളുകൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ഏതൊക്കെ ആപ്പുകളും സംഭാഷണങ്ങളും ബബിൾ ചെയ്യാനാകുമെന്നത് മാനേജ് ചെയ്യാൻ ഇവിടെ ടാപ്പ് ചെയ്യുക"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ബബിൾ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"മാനേജ് ചെയ്യുക"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബിൾ ഡിസ്മിസ് ചെയ്തു."</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index c2081cf..8274f44 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ойлголоо"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Саяхны бөмбөлөг алга байна"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Саяхны бөмбөлгүүд болон үл хэрэгссэн бөмбөлгүүд энд харагдана"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Бөмбөлгүүдийг хүссэн үедээ хянах"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ямар апп болон харилцан ярианууд бөмбөлгөөр харагдахыг энд удирдана уу"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Бөмбөлөг"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Удирдах"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Бөмбөлгийг үл хэрэгссэн."</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index f563ec6..c1f3e12 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"समजले"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"अलीकडील कोणतेही बबल नाहीत"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"बबल कधीही नियंत्रित करा"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"कोणती ॲप्स आणि संभाषणे बबल होऊ शकतात हे व्यवस्थापित करण्यासाठी येथे टॅप करा"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापित करा"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल डिसमिस केला."</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 054d296..82d84e8 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Tiada gelembung terbaharu"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kawal gelembung pada bila-bila masa"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ketik di sini untuk mengurus apl dan perbualan yang boleh menggunakan gelembung"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Gelembung"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Urus"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Gelembung diketepikan."</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 8af8bf4..2e88ab3 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"နားလည်ပြီ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ပူဖောင်းကွက်ကို အချိန်မရွေး ထိန်းချုပ်ရန်"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ပူဖောင်းကွက်သုံးနိုင်သည့် အက်ပ်နှင့် စကားဝိုင်းများ စီမံရန် ဤနေရာကို တို့ပါ"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ပူဖောင်းဖောက်သံ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"စီမံရန်"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 8ac3537..f7ea9ce 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Greit"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ingen nylige bobler"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nylige bobler og avviste bobler vises her"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontroller bobler når som helst"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Trykk her for å administrere hvilke apper og samtaler som kan vises i bobler"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index a46e356a..3f6dc04 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"बुझेँ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हालैका बबलहरू छैनन्"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"जुनसुकै बेला बबलसम्बन्धी सुविधा नियन्त्रण गर्नुहोस्"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"कुन एप र कुराकानी बबल प्रयोग गर्न सक्छन् भन्ने कुराको व्यवस्थापन गर्न यहाँ ट्याप गर्नुहोस्"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापन गर्नुहोस्"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल हटाइयो।"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index ed01315..978ed3c 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen recente bubbels"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recente bubbels en gesloten bubbels zie je hier"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bubbels beheren wanneer je wilt"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tik hier om te beheren welke apps en gesprekken als bubbel kunnen worden getoond"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubbel"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Beheren"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubbel gesloten."</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 8465907..b66448b 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ବୁଝିଗଲି"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ଯେ କୌଣସି ସମୟରେ ବବଲଗୁଡ଼ିକ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"କେଉଁ ଆପ୍ସ ଓ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ବବଲ ହୋଇପାରିବ ତାହା ପରିଚାଳନା କରିବାକୁ ଏଠାରେ ଟାପ କରନ୍ତୁ"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ବବଲ୍"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 243fec3..72cb920 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ਸਮਝ ਲਿਆ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ਬਬਲ ਦੀ ਸੁਵਿਧਾ ਨੂੰ ਕਿਸੇ ਵੀ ਵੇਲੇ ਕੰਟਰੋਲ ਕਰੋ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ਇਹ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਇੱਥੇ ਟੈਪ ਕਰੋ ਕਿ ਕਿਹੜੀਆਂ ਐਪਾਂ ਅਤੇ ਗੱਲਾਂਬਾਤਾਂ ਬਬਲ ਹੋ ਸਕਦੀਆਂ ਹਨ"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"ਬੁਲਬੁਲਾ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 34bc1a0..24c1f14 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Brak ostatnich dymków"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Zarządzaj dymkami, kiedy chcesz"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Kliknij tutaj, aby zarządzać wyświetlaniem aplikacji i rozmów jako dymków"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Dymek"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Zarządzaj"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Zamknięto dymek"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 85f2fa4..6900202 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ok"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e dispensados aparecerão aqui"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controle os balões a qualquer momento"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toque aqui para gerenciar quais apps e conversas podem aparecer em balões"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 083e2e7..853c682 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e ignorados vão aparecer aqui."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controle os balões em qualquer altura"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toque aqui para gerir que apps e conversas podem aparecer em balões"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 85f2fa4..6900202 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ok"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e dispensados aparecerão aqui"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controle os balões a qualquer momento"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toque aqui para gerenciar quais apps e conversas podem aparecer em balões"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 6e8d116..7356f7c 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nu există baloane recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Baloanele recente și baloanele respinse vor apărea aici"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controlează baloanele oricând"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Atinge aici pentru a gestiona aplicațiile și conversațiile care pot apărea în balon"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionează"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index c3cd959..61e3ec9 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ОК"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нет недавних всплывающих чатов"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Здесь будут появляться недавние и скрытые всплывающие чаты."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Всплывающие чаты"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Укажите приложения и разговоры, для которых разрешены всплывающие чаты."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Всплывающая подсказка"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Настроить"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Всплывающий чат закрыт."</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index a1e246a..ac78385 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"තේරුණා"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"මෑත බුබුලු නැත"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"මෑත බුබුලු සහ ඉවත ලූ බුබුලු මෙහි දිස් වනු ඇත"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ඕනෑම වේලාවක බුබුලු පාලනය කරන්න"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"බුබුලු කළ හැකි යෙදුම් සහ සංවාද කළමනාකරණය කිරීමට මෙහි තට්ටු කරන්න"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"බුබුළු"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"කළමනා කරන්න"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"බුබුල ඉවත දමා ඇත."</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index c27425d..d659d51 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Dobre"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Žiadne nedávne bubliny"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ovládajte bubliny kedykoľvek"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Klepnite tu a spravujte, ktoré aplikácie a konverzácie môžu ovládať bubliny"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovať"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina bola zavretá."</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index e3dcca8..91871fb 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"V redu"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ni nedavnih oblačkov"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tukaj bodo prikazani tako nedavni kot tudi opuščeni oblački"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Upravljanje oblačkov"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dotaknite se tukaj za upravljanje aplikacij in pogovorov, ki so lahko prikazani v oblačkih"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Mehurček"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblaček je bil opuščen."</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index b5b2d18..45eb04a 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"E kuptova"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nuk ka flluska të fundit"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrollo flluskat në çdo moment"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Trokit këtu për të menaxhuar aplikacionet e bisedat që do të shfaqen në flluska"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Flluskë"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Menaxho"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Flluska u hoq."</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 3404bca..368df54 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Важи"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нема недавних облачића"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Овде се приказују недавни и одбачени облачићи"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Контролишите облачиће у сваком тренутку"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Додирните овде и одредите које апликације и конверзације могу да имају облачић"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Облачић"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Управљајте"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Облачић је одбачен."</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 1f81e0f..35d5b7a 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Inga nya bubblor"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"De senaste bubblorna och ignorerade bubblor visas här"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Styr bubblor när som helst"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tryck här för att hantera vilka appar och konversationer som får visas i bubblor"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubbla"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Hantera"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubblan ignorerades."</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 8ec4e34..52e0a69 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Nimeelewa"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hakuna viputo vya hivi majuzi"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Dhibiti viputo wakati wowote"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Gusa hapa ili udhibiti programu na mazungumzo yanayoweza kutumia viputo"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Kiputo"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Dhibiti"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Umeondoa kiputo."</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 6a8559d..98a7d67 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"சரி"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"சமீபத்திய குமிழ்கள் இல்லை"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"எப்போது வேண்டுமானாலும் குமிழ்களைக் கட்டுப்படுத்துங்கள்"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"எந்தெந்த ஆப்ஸும் உரையாடல்களும் குமிழியாகலாம் என்பதை நிர்வகிக்க இங்கே தட்டுங்கள்"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"பபிள்"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 1c1e3cb..70f810e 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"అర్థమైంది"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ఇటీవలి బబుల్స్ మరియు తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"బబుల్స్‌ను ఎప్పుడైనా కంట్రోల్ చేయండి"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ఏ యాప్‌లు, సంభాషణలను బబుల్ చేయాలో మేనేజ్ చేయడానికి ఇక్కడ ట్యాప్ చేయండి"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"బబుల్"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"మేనేజ్ చేయండి"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"బబుల్ విస్మరించబడింది."</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index a0f0e27..0efaab2 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"รับทราบ"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ไม่มีบับเบิลเมื่อเร็วๆ นี้"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"บับเบิลที่แสดงและที่ปิดไปเมื่อเร็วๆ นี้จะปรากฏที่นี่"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ควบคุมบับเบิลได้ทุกเมื่อ"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"แตะที่นี่เพื่อจัดการแอปและการสนทนาที่แสดงเป็นบับเบิลได้"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"บับเบิล"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"จัดการ"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ปิดบับเบิลแล้ว"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 9bc17f0..e5d5350 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Walang kamakailang bubble"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Lalabas dito ang mga kamakailang bubble at na-dismiss na bubble"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolin ang mga bubble anumang oras"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Mag-tap dito para pamahalaan ang mga app at conversion na puwedeng mag-bubble"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Pamahalaan"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Na-dismiss na ang bubble."</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 059ec73..8e7f162 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Anladım"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Son kapatılan baloncuk yok"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Baloncukları istediğiniz zaman kontrol edin"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Buraya dokunarak baloncuk olarak gösterilecek uygulama ve görüşmeleri yönetin"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Baloncuk"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Yönet"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon kapatıldı."</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index a4a4a78..5c7c6c4 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Зрозуміло"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Немає нещодавніх спливаючих чатів"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Контроль спливаючих чатів"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Натисніть тут, щоб вибрати, для яких додатків і розмов дозволити спливаючі чати"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Спливаюче сповіщення"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Налаштувати"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Спливаюче сповіщення закрито."</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index b25f13e..451d048 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"سمجھ آ گئی"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"کوئی حالیہ بلبلہ نہیں"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"کسی بھی وقت بلبلے کو کنٹرول کریں"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"یہ نظم کرنے کے لیے یہاں تھپتھپائیں کہ کون سی ایپس اور گفتگوئیں بلبلہ سکتی ہیں"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"بلبلہ"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"نظم کریں"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"بلبلہ برخاست کر دیا گیا۔"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 5acf729..4211ea7 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hech qanday bulutcha topilmadi"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Eng oxirgi va yopilgan bulutchali chatlar shu yerda chiqadi"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bulutchalardagi bildirishnomalar"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Bulutchalarda bildirishnomalar chiqishiga ruxsat beruvchi ilova va suhbatlarni tanlang."</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Pufaklar"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Boshqarish"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulutcha yopildi."</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 0777abc..0a0205d 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Đã hiểu"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Không có bong bóng trò chuyện nào gần đây"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kiểm soát bong bóng bất cứ lúc nào"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Nhấn vào đây để quản lý việc dùng bong bóng cho các ứng dụng và cuộc trò chuyện"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index cde5fe3..29dc077 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"知道了"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近没有对话泡"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"此处会显示最近的对话泡和已关闭的对话泡"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"随时控制对话泡"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"点按此处即可管理哪些应用和对话可以显示对话泡"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"气泡"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭对话泡。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index fcb0c91..0755d61 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"知道了"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"沒有最近曾使用的小視窗"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近使用和關閉的小視窗會在這裡顯示"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"隨時控制對話氣泡"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"輕按這裡即可管理哪些應用程式和對話可以使用對話氣泡"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"氣泡"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"對話氣泡已關閉。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index f272e91..f931883 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"我知道了"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近沒有任何對話框"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"你隨時可以控管對話框的各項設定"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"輕觸這裡即可管理哪些應用程式和對話可顯示對話框"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"泡泡"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index c1ba6ee..3ba0abe 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -76,10 +76,8 @@
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ngiyezwa"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Awekho amabhamuza akamuva"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Amabhamuza akamuva namabhamuza asusiwe azobonakala lapha."</string>
-    <!-- no translation found for bubble_bar_education_manage_title (6148404487810835924) -->
-    <skip />
-    <!-- no translation found for bubble_bar_education_manage_text (3199732148641842038) -->
-    <skip />
+    <string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Lawula amabhamuza noma nini"</string>
+    <string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Thepha lapha ukuze ulawule ukuthi yimaphi ama-app kanye nezingxoxo ezingenza amabhamuza"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Ibhamuza"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Phatha"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ibhamuza licashisiwe."</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index d0c0c02..cba86c8 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -428,9 +428,12 @@
     <!-- The height of the handle menu's "Windowing" pill in desktop mode. -->
     <dimen name="desktop_mode_handle_menu_windowing_pill_height">52dp</dimen>
 
-    <!-- The height of the handle menu's "More Actions" pill in desktop mode. -->
+    <!-- The height of the handle menu's "More Actions" pill in desktop mode, but not freeform. -->
     <dimen name="desktop_mode_handle_menu_more_actions_pill_height">156dp</dimen>
 
+    <!-- The height of the handle menu's "More Actions" pill in freeform desktop windowing mode. -->
+    <dimen name="desktop_mode_handle_menu_more_actions_pill_freeform_height">104dp</dimen>
+
     <!-- The top margin of the handle menu in desktop mode. -->
     <dimen name="desktop_mode_handle_menu_margin_top">4dp</dimen>
 
@@ -450,6 +453,10 @@
 
     <dimen name="freeform_resize_corner">44dp</dimen>
 
+    <!-- The width of the area at the sides of the screen where a freeform task will transition to
+    split select if dragged until the touch input is within the range. -->
+    <dimen name="desktop_mode_transition_area_width">32dp</dimen>
+
     <!-- The height of the area at the top of the screen where a freeform task will transition to
     fullscreen if dragged until the top bound of the task is within the area. -->
     <dimen name="desktop_mode_transition_area_height">16dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 9aac694..0479576 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -103,7 +103,7 @@
         default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {}
         /** Whether this task listener supports compat UI. */
         default boolean supportCompatUI() {
-            // All TaskListeners should support compat UI except PIP.
+            // All TaskListeners should support compat UI except PIP and StageCoordinator.
             return true;
         }
         /** Attaches a child window surface to the task surface. */
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 9a2b812..85ea809 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
@@ -973,9 +973,9 @@
         pw.print("  suppressNotif: "); pw.println(shouldSuppressNotification());
         pw.print("  autoExpand:    "); pw.println(shouldAutoExpand());
         pw.print("  isDismissable: "); pw.println(mIsDismissable);
-        pw.println("  bubbleMetadataFlagListener null: " + (mBubbleMetadataFlagListener == null));
+        pw.println("  bubbleMetadataFlagListener null?: " + (mBubbleMetadataFlagListener == null));
         if (mExpandedView != null) {
-            mExpandedView.dump(pw);
+            mExpandedView.dump(pw, "  ");
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 8400dde..dfdc79e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.bubbles;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
@@ -115,6 +114,7 @@
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.taskview.TaskView;
 import com.android.wm.shell.taskview.TaskViewTransitions;
+import com.android.wm.shell.transition.Transitions;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -143,6 +143,8 @@
     // Should match with PhoneWindowManager
     private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
     private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
+    private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+    private static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
 
     /**
      * Common interface to send updates to bubble views.
@@ -182,6 +184,7 @@
     private final ShellTaskOrganizer mTaskOrganizer;
     private final DisplayController mDisplayController;
     private final TaskViewTransitions mTaskViewTransitions;
+    private final Transitions mTransitions;
     private final SyncTransactionQueue mSyncQueue;
     private final ShellController mShellController;
     private final ShellCommandHandler mShellCommandHandler;
@@ -282,6 +285,7 @@
             @ShellMainThread Handler mainHandler,
             @ShellBackgroundThread ShellExecutor bgExecutor,
             TaskViewTransitions taskViewTransitions,
+            Transitions transitions,
             SyncTransactionQueue syncQueue,
             IWindowManager wmService,
             BubbleProperties bubbleProperties) {
@@ -317,6 +321,7 @@
                         com.android.internal.R.dimen.importance_ring_stroke_width));
         mDisplayController = displayController;
         mTaskViewTransitions = taskViewTransitions;
+        mTransitions = transitions;
         mOneHandedOptional = oneHandedOptional;
         mDragAndDropController = dragAndDropController;
         mSyncQueue = syncQueue;
@@ -416,23 +421,9 @@
             }
         }, mMainHandler);
 
-        mTaskStackListener.addListener(new TaskStackListenerCallback() {
-            @Override
-            public void onTaskMovedToFront(int taskId) {
-                mMainExecutor.execute(() -> {
-                    int expandedId = INVALID_TASK_ID;
-                    if (mStackView != null && mStackView.getExpandedBubble() != null
-                            && isStackExpanded()
-                            && !mStackView.isExpansionAnimating()
-                            && !mStackView.isSwitchAnimating()) {
-                        expandedId = mStackView.getExpandedBubble().getTaskId();
-                    }
-                    if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
-                        mBubbleData.setExpanded(false);
-                    }
-                });
-            }
+        mTransitions.registerObserver(new BubblesTransitionObserver(this, mBubbleData));
 
+        mTaskStackListener.addListener(new TaskStackListenerCallback() {
             @Override
             public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
                     boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
@@ -883,8 +874,10 @@
 
             String action = intent.getAction();
             String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
-            if ((Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
-                    && SYSTEM_DIALOG_REASON_GESTURE_NAV.equals(reason))
+            boolean validReasonToCollapse = SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)
+                    || SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)
+                    || SYSTEM_DIALOG_REASON_GESTURE_NAV.equals(reason);
+            if ((Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) && validReasonToCollapse)
                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
                 mMainExecutor.execute(() -> collapseStack());
             }
@@ -1961,6 +1954,15 @@
         }
     }
 
+    /**
+     * Returns whether the stack is animating or not.
+     */
+    public boolean isStackAnimating() {
+        return mStackView != null
+                && (mStackView.isExpansionAnimating()
+                || mStackView.isSwitchAnimating());
+    }
+
     @VisibleForTesting
     @Nullable
     public BubbleStackView getStackView() {
@@ -1989,13 +1991,20 @@
      * Description of current bubble state.
      */
     private void dump(PrintWriter pw, String prefix) {
-        pw.println("BubbleController state:");
+        pw.print(prefix); pw.println("BubbleController state:");
+        pw.print(prefix); pw.println("  currentUserId= " + mCurrentUserId);
+        pw.print(prefix); pw.println("  isStatusBarShade= " + mIsStatusBarShade);
+        pw.print(prefix); pw.println("  isShowingAsBubbleBar= " + isShowingAsBubbleBar());
+        pw.println();
+
         mBubbleData.dump(pw);
         pw.println();
+
         if (mStackView != null) {
             mStackView.dump(pw);
         }
         pw.println();
+
         mImpl.mCachedState.dump(pw);
     }
 
@@ -2244,8 +2253,7 @@
                 pw.println("mIsStackExpanded: " + mIsStackExpanded);
                 pw.println("mSelectedBubbleKey: " + mSelectedBubbleKey);
 
-                pw.print("mSuppressedBubbleKeys: ");
-                pw.println(mSuppressedBubbleKeys.size());
+                pw.println("mSuppressedBubbleKeys: " + mSuppressedBubbleKeys.size());
                 for (String key : mSuppressedBubbleKeys) {
                     pw.println("   suppressing: " + key);
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index cc8f50e..c6f74af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -1231,29 +1231,30 @@
      * Description of current bubble data state.
      */
     public void dump(PrintWriter pw) {
-        pw.print("selected: ");
+        pw.println("BubbleData state:");
+        pw.print("  selected: ");
         pw.println(mSelectedBubble != null
                 ? mSelectedBubble.getKey()
                 : "null");
-        pw.print("expanded: ");
+        pw.print("  expanded: ");
         pw.println(mExpanded);
 
-        pw.print("stack bubble count:    ");
+        pw.print("Stack bubble count: ");
         pw.println(mBubbles.size());
         for (Bubble bubble : mBubbles) {
             bubble.dump(pw);
         }
 
-        pw.print("overflow bubble count:    ");
+        pw.print("Overflow bubble count: ");
         pw.println(mOverflowBubbles.size());
         for (Bubble bubble : mOverflowBubbles) {
             bubble.dump(pw);
         }
 
-        pw.print("summaryKeys: ");
+        pw.print("SummaryKeys: ");
         pw.println(mSuppressedGroupKeys.size());
         for (String key : mSuppressedGroupKeys.keySet()) {
-            pw.println("   suppressing: " + key);
+            pw.println("     suppressing: " + key);
         }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index 76662c4..1c0e052 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
@@ -77,20 +77,25 @@
 
     static String formatBubblesString(List<Bubble> bubbles, BubbleViewProvider selected) {
         StringBuilder sb = new StringBuilder();
-        for (Bubble bubble : bubbles) {
+        for (int i = 0; i < bubbles.size(); i++) {
+            Bubble bubble = bubbles.get(i);
             if (bubble == null) {
-                sb.append("   <null> !!!!!\n");
+                sb.append("   <null> !!!!!");
             } else {
                 boolean isSelected = (selected != null
-                        && selected.getKey() != BubbleOverflow.KEY
+                        && !BubbleOverflow.KEY.equals(selected.getKey())
                         && bubble == selected);
                 String arrow = isSelected ? "=>" : "  ";
-                sb.append(String.format("%s Bubble{act=%12d, showInShade=%d, key=%s}\n",
+
+                sb.append(String.format("%s Bubble{act=%12d, showInShade=%d, key=%s}",
                         arrow,
                         bubble.getLastActivity(),
                         (bubble.showInShade() ? 1 : 0),
                         bubble.getKey()));
             }
+            if (i != bubbles.size() - 1) {
+                sb.append("\n");
+            }
         }
         return sb.toString();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index e698601..37bcf1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -1094,9 +1094,9 @@
     /**
      * Description of current expanded view state.
      */
-    public void dump(@NonNull PrintWriter pw) {
-        pw.print("BubbleExpandedView");
-        pw.print("  taskId:               "); pw.println(mTaskId);
-        pw.print("  stackView:            "); pw.println(mStackView);
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+        pw.print(prefix); pw.println("BubbleExpandedView:");
+        pw.print(prefix); pw.print("  taskId: "); pw.println(mTaskId);
+        pw.print(prefix); pw.print("  stackView: "); pw.println(mStackView);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 52c9bf8..093ecb1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -305,8 +305,7 @@
 
         String bubblesOnScreen = BubbleDebugConfig.formatBubblesString(
                 getBubblesOnScreen(), getExpandedBubble());
-        pw.print("  stack visibility :       "); pw.println(getVisibility());
-        pw.print("  bubbles on screen:       "); pw.println(bubblesOnScreen);
+        pw.println("  bubbles on screen:       "); pw.println(bubblesOnScreen);
         pw.print("  gestureInProgress:       "); pw.println(mIsGestureInProgress);
         pw.print("  showingDismiss:          "); pw.println(mDismissView.isShowing());
         pw.print("  isExpansionAnimating:    "); pw.println(mIsExpansionAnimating);
@@ -314,7 +313,8 @@
         pw.print("  expandedContainerAlpha:  "); pw.println(mExpandedViewContainer.getAlpha());
         pw.print("  expandedContainerMatrix: ");
         pw.println(mExpandedViewContainer.getAnimationMatrix());
-
+        pw.print("  stack visibility :       "); pw.println(getVisibility());
+        pw.print("  temporarilyInvisible:    "); pw.println(mTemporarilyInvisible);
         mStackAnimationController.dump(pw);
         mExpandedAnimationController.dump(pw);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java
new file mode 100644
index 0000000..9e8a385
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
+import android.app.ActivityManager;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
+
+import androidx.annotation.NonNull;
+
+import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.TransitionUtil;
+
+/**
+ * Observer used to identify tasks that are opening or moving to front. If a bubble activity is
+ * currently opened when this happens, we'll collapse the bubbles.
+ */
+public class BubblesTransitionObserver implements Transitions.TransitionObserver {
+
+    private BubbleController mBubbleController;
+    private BubbleData mBubbleData;
+
+    public BubblesTransitionObserver(BubbleController controller,
+            BubbleData bubbleData) {
+        mBubbleController = controller;
+        mBubbleData = bubbleData;
+    }
+
+    @Override
+    public void onTransitionReady(@NonNull IBinder transition, @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        for (TransitionInfo.Change change : info.getChanges()) {
+            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
+            // We only care about opens / move to fronts when bubbles are expanded & not animating.
+            if (taskInfo == null
+                    || taskInfo.taskId == INVALID_TASK_ID
+                    || !TransitionUtil.isOpeningType(change.getMode())
+                    || mBubbleController.isStackAnimating()
+                    || !mBubbleData.isExpanded()
+                    || mBubbleData.getSelectedBubble() == null) {
+                continue;
+            }
+            int expandedId = mBubbleData.getSelectedBubble().getTaskId();
+            // If the task id that's opening is the same as the expanded bubble, skip collapsing
+            // because it is our bubble that is opening.
+            if (expandedId != INVALID_TASK_ID && expandedId != taskInfo.taskId) {
+                mBubbleData.setExpanded(false);
+            }
+        }
+    }
+
+    @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) {
+
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
index 72702e7..b828aac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayChangeController.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.Slog;
 import android.view.IDisplayChangeWindowCallback;
 import android.view.IDisplayChangeWindowController;
@@ -40,6 +41,7 @@
  */
 public class DisplayChangeController {
     private static final String TAG = DisplayChangeController.class.getSimpleName();
+    private static final String HANDLE_DISPLAY_CHANGE_TRACE_TAG = "HandleRemoteDisplayChange";
 
     private final ShellExecutor mMainExecutor;
     private final IWindowManager mWmService;
@@ -81,9 +83,15 @@
     /** Query all listeners for changes that should happen on display change. */
     void dispatchOnDisplayChange(WindowContainerTransaction outWct, int displayId,
             int fromRotation, int toRotation, DisplayAreaInfo newDisplayAreaInfo) {
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+            Trace.beginSection("dispatchOnDisplayChange");
+        }
         for (OnDisplayChangingListener c : mDisplayChangeListener) {
             c.onDisplayChange(displayId, fromRotation, toRotation, newDisplayAreaInfo, outWct);
         }
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+            Trace.endSection();
+        }
     }
 
     private void onDisplayChange(int displayId, int fromRotation, int toRotation,
@@ -94,6 +102,10 @@
             callback.continueDisplayChange(t);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to continue handling display change", e);
+        } finally {
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                Trace.endAsyncSection(HANDLE_DISPLAY_CHANGE_TRACE_TAG, callback.hashCode());
+            }
         }
     }
 
@@ -103,6 +115,9 @@
         @Override
         public void onDisplayChange(int displayId, int fromRotation, int toRotation,
                 DisplayAreaInfo newDisplayAreaInfo, IDisplayChangeWindowCallback callback) {
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                Trace.beginAsyncSection(HANDLE_DISPLAY_CHANGE_TRACE_TAG, callback.hashCode());
+            }
             mMainExecutor.execute(() -> DisplayChangeController.this
                     .onDisplayChange(displayId, fromRotation, toRotation,
                             newDisplayAreaInfo, callback));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index cbff464..77aefc8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -208,7 +208,7 @@
     }
 
     private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
-        return  taskInfo.topActivityEligibleForUserAspectRatioButton
+        return taskInfo.topActivityEligibleForUserAspectRatioButton
                 && (taskInfo.topActivityBoundsLetterboxed
                     || taskInfo.isUserFullscreenOverrideEnabled);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 1c2cee5..998cd5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -72,7 +72,6 @@
 import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
 import com.android.wm.shell.desktopmode.DesktopMode;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -109,13 +108,13 @@
 import com.android.wm.shell.unfold.UnfoldTransitionHandler;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
+import java.util.Optional;
+
 import dagger.BindsOptionalOf;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
-import java.util.Optional;
-
 /**
  * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
  * accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -800,30 +799,10 @@
     @WMSingleton
     @Provides
     static Optional<DesktopMode> provideDesktopMode(
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController) {
-        if (DesktopModeStatus.isProto2Enabled()) {
-            return desktopTasksController.map(DesktopTasksController::asDesktopMode);
-        }
-        return desktopModeController.map(DesktopModeController::asDesktopMode);
+        return desktopTasksController.map(DesktopTasksController::asDesktopMode);
     }
 
-    @BindsOptionalOf
-    @DynamicOverride
-    abstract DesktopModeController optionalDesktopModeController();
-
-    @WMSingleton
-    @Provides
-    static Optional<DesktopModeController> provideDesktopModeController(
-            @DynamicOverride Optional<Lazy<DesktopModeController>> desktopModeController) {
-        // Use optional-of-lazy for the dependency that this provider relies on.
-        // Lazy ensures that this provider will not be the cause the dependency is created
-        // when it will not be returned due to the condition below.
-        if (DesktopModeStatus.isProto1Enabled()) {
-            return desktopModeController.map(Lazy::get);
-        }
-        return Optional.empty();
-    }
 
     @BindsOptionalOf
     @DynamicOverride
@@ -836,7 +815,7 @@
         // Use optional-of-lazy for the dependency that this provider relies on.
         // Lazy ensures that this provider will not be the cause the dependency is created
         // when it will not be returned due to the condition below.
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             return desktopTasksController.map(Lazy::get);
         }
         return Optional.empty();
@@ -853,7 +832,7 @@
         // Use optional-of-lazy for the dependency that this provider relies on.
         // Lazy ensures that this provider will not be the cause the dependency is created
         // when it will not be returned due to the condition below.
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             return desktopModeTaskRepository.map(Lazy::get);
         }
         return Optional.empty();
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 93ce91f..e9f3e1a 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
@@ -54,7 +54,6 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
 import com.android.wm.shell.dagger.pip.PipModule;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -167,6 +166,7 @@
             @ShellMainThread Handler mainHandler,
             @ShellBackgroundThread ShellExecutor bgExecutor,
             TaskViewTransitions taskViewTransitions,
+            Transitions transitions,
             SyncTransactionQueue syncQueue,
             IWindowManager wmService) {
         return new BubbleController(context, shellInit, shellCommandHandler, shellController, data,
@@ -176,7 +176,8 @@
                 statusBarService, windowManager, windowManagerShellWrapper, userManager,
                 launcherApps, logger, taskStackListener, organizer, positioner, displayController,
                 oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
-                taskViewTransitions, syncQueue, wmService, ProdBubbleProperties.INSTANCE);
+                taskViewTransitions, transitions, syncQueue, wmService,
+                ProdBubbleProperties.INSTANCE);
     }
 
     //
@@ -195,10 +196,9 @@
             ShellController shellController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             return new DesktopModeWindowDecorViewModel(
                     context,
                     mainHandler,
@@ -209,7 +209,6 @@
                     shellController,
                     syncQueue,
                     transitions,
-                    desktopModeController,
                     desktopTasksController,
                     rootTaskDisplayAreaOrganizer);
         }
@@ -351,13 +350,12 @@
             @Nullable PipTransitionController pipTransitionController,
             Optional<RecentsTransitionHandler> recentsTransitionHandler,
             KeyguardTransitionHandler keyguardTransitionHandler,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             Optional<UnfoldTransitionHandler> unfoldHandler,
             Transitions transitions) {
         return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
                 pipTransitionController, recentsTransitionHandler,
-                keyguardTransitionHandler, desktopModeController, desktopTasksController,
+                keyguardTransitionHandler, desktopTasksController,
                 unfoldHandler);
     }
 
@@ -469,24 +467,6 @@
     @WMSingleton
     @Provides
     @DynamicOverride
-    static DesktopModeController provideDesktopModeController(Context context,
-            ShellInit shellInit,
-            ShellController shellController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
-            Transitions transitions,
-            @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
-            @ShellMainThread Handler mainHandler,
-            @ShellMainThread ShellExecutor mainExecutor
-    ) {
-        return new DesktopModeController(context, shellInit, shellController, shellTaskOrganizer,
-                rootTaskDisplayAreaOrganizer, transitions, desktopModeTaskRepository, mainHandler,
-                mainExecutor);
-    }
-
-    @WMSingleton
-    @Provides
-    @DynamicOverride
     static DesktopTasksController provideDesktopTasksController(
             Context context,
             ShellInit shellInit,
@@ -551,8 +531,7 @@
     @ShellCreateTriggerOverride
     @Provides
     static Object provideIndependentShellComponentsToCreate(
-            DefaultMixedHandler defaultMixedHandler,
-            Optional<DesktopModeController> desktopModeController) {
+            DefaultMixedHandler defaultMixedHandler) {
         return new Object();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
deleted file mode 100644
index 5b24d7a..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ /dev/null
@@ -1,557 +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.wm.shell.desktopmode;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.WindowConfiguration;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.graphics.Region;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.window.DisplayAreaInfo;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.BinderThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.ExternalInterfaceBinder;
-import com.android.wm.shell.common.RemoteCallable;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.sysui.ShellController;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-/**
- * Handles windowing changes when desktop mode system setting changes
- */
-public class DesktopModeController implements RemoteCallable<DesktopModeController>,
-        Transitions.TransitionHandler {
-
-    private final Context mContext;
-    private final ShellController mShellController;
-    private final ShellTaskOrganizer mShellTaskOrganizer;
-    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
-    private final Transitions mTransitions;
-    private final DesktopModeTaskRepository mDesktopModeTaskRepository;
-    private final ShellExecutor mMainExecutor;
-    private final DesktopModeImpl mDesktopModeImpl = new DesktopModeImpl();
-    private final SettingsObserver mSettingsObserver;
-
-    public DesktopModeController(Context context,
-            ShellInit shellInit,
-            ShellController shellController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
-            Transitions transitions,
-            DesktopModeTaskRepository desktopModeTaskRepository,
-            @ShellMainThread Handler mainHandler,
-            @ShellMainThread ShellExecutor mainExecutor) {
-        mContext = context;
-        mShellController = shellController;
-        mShellTaskOrganizer = shellTaskOrganizer;
-        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
-        mTransitions = transitions;
-        mDesktopModeTaskRepository = desktopModeTaskRepository;
-        mMainExecutor = mainExecutor;
-        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
-        if (DesktopModeStatus.isProto1Enabled()) {
-            shellInit.addInitCallback(this::onInit, this);
-        }
-    }
-
-    private void onInit() {
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_DESKTOP_MODE,
-                this::createExternalInterface, this);
-        mSettingsObserver.observe();
-        if (DesktopModeStatus.isActive(mContext)) {
-            updateDesktopModeActive(true);
-        }
-        mTransitions.addHandler(this);
-    }
-
-    @Override
-    public Context getContext() {
-        return mContext;
-    }
-
-    @Override
-    public ShellExecutor getRemoteCallExecutor() {
-        return mMainExecutor;
-    }
-
-    /**
-     * Get connection interface between sysui and shell
-     */
-    public DesktopMode asDesktopMode() {
-        return mDesktopModeImpl;
-    }
-
-    /**
-     * Creates a new instance of the external interface to pass to another process.
-     */
-    private ExternalInterfaceBinder createExternalInterface() {
-        return new IDesktopModeImpl(this);
-    }
-
-    /**
-     * Adds a listener to find out about changes in the visibility of freeform tasks.
-     *
-     * @param listener the listener to add.
-     * @param callbackExecutor the executor to call the listener on.
-     */
-    public void addVisibleTasksListener(DesktopModeTaskRepository.VisibleTasksListener listener,
-            Executor callbackExecutor) {
-        mDesktopModeTaskRepository.addVisibleTasksListener(listener, callbackExecutor);
-    }
-
-    /**
-     * Adds a listener to track changes to corners of desktop mode tasks.
-     * @param listener the listener to add.
-     * @param callbackExecutor the executor to call the listener on.
-     */
-    public void addTaskCornerListener(Consumer<Region> listener,
-            Executor callbackExecutor) {
-        mDesktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor);
-    }
-
-    @VisibleForTesting
-    void updateDesktopModeActive(boolean active) {
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeActive: active=%s", active);
-
-        int displayId = mContext.getDisplayId();
-
-        ArrayList<RunningTaskInfo> runningTasks = mShellTaskOrganizer.getRunningTasks(displayId);
-
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        // Reset freeform windowing mode that is set per task level so tasks inherit it
-        clearFreeformForStandardTasks(runningTasks, wct);
-        if (active) {
-            moveHomeBehindVisibleTasks(runningTasks, wct);
-            setDisplayAreaWindowingMode(displayId, WINDOWING_MODE_FREEFORM, wct);
-        } else {
-            clearBoundsForStandardTasks(runningTasks, wct);
-            setDisplayAreaWindowingMode(displayId, WINDOWING_MODE_FULLSCREEN, wct);
-        }
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mTransitions.startTransition(TRANSIT_CHANGE, wct, null);
-        } else {
-            mRootTaskDisplayAreaOrganizer.applyTransaction(wct);
-        }
-    }
-
-    private WindowContainerTransaction clearBoundsForStandardTasks(
-            ArrayList<RunningTaskInfo> runningTasks, WindowContainerTransaction wct) {
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks");
-        for (RunningTaskInfo taskInfo : runningTasks) {
-            if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
-                ProtoLog.v(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
-                        taskInfo.token, taskInfo);
-                wct.setBounds(taskInfo.token, null);
-            }
-        }
-        return wct;
-    }
-
-    private void clearFreeformForStandardTasks(ArrayList<RunningTaskInfo> runningTasks,
-            WindowContainerTransaction wct) {
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks");
-        for (RunningTaskInfo taskInfo : runningTasks) {
-            if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
-                    && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
-                ProtoLog.v(WM_SHELL_DESKTOP_MODE,
-                        "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
-                        taskInfo);
-                wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
-            }
-        }
-    }
-
-    private void moveHomeBehindVisibleTasks(ArrayList<RunningTaskInfo> runningTasks,
-            WindowContainerTransaction wct) {
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks");
-        RunningTaskInfo homeTask = null;
-        ArrayList<RunningTaskInfo> visibleTasks = new ArrayList<>();
-        for (RunningTaskInfo taskInfo : runningTasks) {
-            if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
-                homeTask = taskInfo;
-            } else if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
-                    && taskInfo.isVisible()) {
-                visibleTasks.add(taskInfo);
-            }
-        }
-        if (homeTask == null) {
-            ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks: home task not found");
-        } else {
-            ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks: visible tasks %d",
-                    visibleTasks.size());
-            wct.reorder(homeTask.getToken(), true /* onTop */);
-            for (RunningTaskInfo task : visibleTasks) {
-                wct.reorder(task.getToken(), true /* onTop */);
-            }
-        }
-    }
-
-    private void setDisplayAreaWindowingMode(int displayId,
-            @WindowConfiguration.WindowingMode int windowingMode, WindowContainerTransaction wct) {
-        DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
-                displayId);
-        if (displayAreaInfo == null) {
-            ProtoLog.e(WM_SHELL_DESKTOP_MODE,
-                    "unable to update windowing mode for display %d display not found", displayId);
-            return;
-        }
-
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE,
-                "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId,
-                displayAreaInfo.configuration.windowConfiguration.getWindowingMode(),
-                windowingMode);
-
-        wct.setWindowingMode(displayAreaInfo.token, windowingMode);
-    }
-
-    /**
-     * Show apps on desktop
-     */
-    void showDesktopApps(int displayId) {
-        // Bring apps to front, ignoring their visibility status to always ensure they are on top.
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        bringDesktopAppsToFront(displayId, wct);
-
-        if (!wct.isEmpty()) {
-            if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-                // TODO(b/268662477): add animation for the transition
-                mTransitions.startTransition(TRANSIT_NONE, wct, null /* handler */);
-            } else {
-                mShellTaskOrganizer.applyTransaction(wct);
-            }
-        }
-    }
-
-    /** Get number of tasks that are marked as visible */
-    int getVisibleTaskCount(int displayId) {
-        return mDesktopModeTaskRepository.getVisibleTaskCount(displayId);
-    }
-
-    private void bringDesktopAppsToFront(int displayId, WindowContainerTransaction wct) {
-        final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks(displayId);
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());
-
-        final List<RunningTaskInfo> taskInfos = new ArrayList<>();
-        for (Integer taskId : activeTasks) {
-            RunningTaskInfo taskInfo = mShellTaskOrganizer.getRunningTaskInfo(taskId);
-            if (taskInfo != null) {
-                taskInfos.add(taskInfo);
-            }
-        }
-
-        if (taskInfos.isEmpty()) {
-            return;
-        }
-
-        moveHomeTaskToFront(wct);
-
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE,
-                "bringDesktopAppsToFront: reordering all active tasks to the front");
-        final List<Integer> allTasksInZOrder =
-                mDesktopModeTaskRepository.getFreeformTasksInZOrder();
-        // Sort by z-order, bottom to top, so that the top-most task is reordered to the top last
-        // in the WCT.
-        taskInfos.sort(Comparator.comparingInt(task -> -allTasksInZOrder.indexOf(task.taskId)));
-        for (RunningTaskInfo task : taskInfos) {
-            wct.reorder(task.token, true);
-        }
-    }
-
-    private void moveHomeTaskToFront(WindowContainerTransaction wct) {
-        for (RunningTaskInfo task : mShellTaskOrganizer.getRunningTasks(mContext.getDisplayId())) {
-            if (task.getActivityType() == ACTIVITY_TYPE_HOME) {
-                wct.reorder(task.token, true /* onTop */);
-                return;
-            }
-        }
-    }
-
-    /**
-     * Update corner rects stored for a specific task
-     * @param taskId task to update
-     * @param taskCorners task's new corner handles
-     */
-    public void onTaskCornersChanged(int taskId, Region taskCorners) {
-        mDesktopModeTaskRepository.updateTaskCorners(taskId, taskCorners);
-    }
-
-    /**
-     * Remove corners saved for a task. Likely used due to task closure.
-     * @param taskId task to remove
-     */
-    public void removeCornersForTask(int taskId) {
-        mDesktopModeTaskRepository.removeTaskCorners(taskId);
-    }
-
-    /**
-     * Moves a specifc task to the front.
-     * @param taskInfo the task to show in front.
-     */
-    public void moveTaskToFront(RunningTaskInfo taskInfo) {
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        wct.reorder(taskInfo.token, true /* onTop */);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mTransitions.startTransition(TRANSIT_TO_FRONT, wct, null);
-        } else {
-            mShellTaskOrganizer.applyTransaction(wct);
-        }
-    }
-
-    /**
-     * Turn desktop mode on or off
-     * @param active the desired state for desktop mode setting
-     */
-    public void setDesktopModeActive(boolean active) {
-        int value = active ? 1 : 0;
-        Settings.System.putInt(mContext.getContentResolver(), Settings.System.DESKTOP_MODE, value);
-    }
-
-    /**
-     * Returns the windowing mode of the display area with the specified displayId.
-     * @param displayId
-     * @return
-     */
-    public int getDisplayAreaWindowingMode(int displayId) {
-        return mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
-                .configuration.windowConfiguration.getWindowingMode();
-    }
-
-    @Override
-    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction,
-            @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        // This handler should never be the sole handler, so should not animate anything.
-        return false;
-    }
-
-    @Nullable
-    @Override
-    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
-            @NonNull TransitionRequestInfo request) {
-        RunningTaskInfo triggerTask = request.getTriggerTask();
-        // Only do anything if we are in desktop mode and opening/moving-to-front a task/app in
-        // freeform
-        if (!DesktopModeStatus.isActive(mContext)) {
-            ProtoLog.d(WM_SHELL_DESKTOP_MODE,
-                    "skip shell transition request: desktop mode not active");
-            return null;
-        }
-        if (request.getType() != TRANSIT_OPEN && request.getType() != TRANSIT_TO_FRONT) {
-            ProtoLog.d(WM_SHELL_DESKTOP_MODE,
-                    "skip shell transition request: unsupported type %s",
-                    WindowManager.transitTypeToString(request.getType()));
-            return null;
-        }
-        if (triggerTask == null || triggerTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
-            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "skip shell transition request: not freeform task");
-            return null;
-        }
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "handle shell transition request: %s", request);
-
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        bringDesktopAppsToFront(triggerTask.displayId, wct);
-        wct.reorder(triggerTask.token, true /* onTop */);
-
-        return wct;
-    }
-
-    /**
-     * Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
-     * This is intended to be used when desktop mode is part of another animation but isn't, itself,
-     * animating.
-     */
-    public void syncSurfaceState(@NonNull TransitionInfo info,
-            SurfaceControl.Transaction finishTransaction) {
-        // Add rounded corners to freeform windows
-        final TypedArray ta = mContext.obtainStyledAttributes(
-                new int[]{android.R.attr.dialogCornerRadius});
-        final int cornerRadius = ta.getDimensionPixelSize(0, 0);
-        ta.recycle();
-        for (TransitionInfo.Change change: info.getChanges()) {
-            if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-                finishTransaction.setCornerRadius(change.getLeash(), cornerRadius);
-            }
-        }
-    }
-
-    /**
-     * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
-     */
-    private final class SettingsObserver extends ContentObserver {
-
-        private final Uri mDesktopModeSetting = Settings.System.getUriFor(
-                Settings.System.DESKTOP_MODE);
-
-        private final Context mContext;
-
-        SettingsObserver(Context context, Handler handler) {
-            super(handler);
-            mContext = context;
-        }
-
-        public void observe() {
-            // TODO(b/242867463): listen for setting change for all users
-            mContext.getContentResolver().registerContentObserver(mDesktopModeSetting,
-                    false /* notifyForDescendants */, this /* observer */, UserHandle.USER_CURRENT);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, @Nullable Uri uri) {
-            if (mDesktopModeSetting.equals(uri)) {
-                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Received update for desktop mode setting");
-                desktopModeSettingChanged();
-            }
-        }
-
-        private void desktopModeSettingChanged() {
-            boolean enabled = DesktopModeStatus.isActive(mContext);
-            updateDesktopModeActive(enabled);
-        }
-    }
-
-    /**
-     * The interface for calls from outside the shell, within the host process.
-     */
-    @ExternalThread
-    private final class DesktopModeImpl implements DesktopMode {
-
-        @Override
-        public void addVisibleTasksListener(
-                DesktopModeTaskRepository.VisibleTasksListener listener,
-                Executor callbackExecutor) {
-            mMainExecutor.execute(() -> {
-                DesktopModeController.this.addVisibleTasksListener(listener, callbackExecutor);
-            });
-        }
-
-        @Override
-        public void addDesktopGestureExclusionRegionListener(Consumer<Region> listener,
-                Executor callbackExecutor) {
-            mMainExecutor.execute(() -> {
-                DesktopModeController.this.addTaskCornerListener(listener, callbackExecutor);
-            });
-        }
-    }
-
-    /**
-     * The interface for calls from outside the host process.
-     */
-    @BinderThread
-    private static class IDesktopModeImpl extends IDesktopMode.Stub
-            implements ExternalInterfaceBinder {
-
-        private DesktopModeController mController;
-
-        IDesktopModeImpl(DesktopModeController controller) {
-            mController = controller;
-        }
-
-        /**
-         * Invalidates this instance, preventing future calls from updating the controller.
-         */
-        @Override
-        public void invalidate() {
-            mController = null;
-        }
-
-        @Override
-        public void showDesktopApps(int displayId) {
-            executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
-                    controller -> controller.showDesktopApps(displayId));
-        }
-
-        @Override
-        public void showDesktopApp(int taskId) throws RemoteException {
-            // TODO
-        }
-
-        @Override
-        public int getVisibleTaskCount(int displayId) throws RemoteException {
-            int[] result = new int[1];
-            executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
-                    controller -> result[0] = controller.getVisibleTaskCount(displayId),
-                    true /* blocking */
-            );
-            return result[0];
-        }
-
-        @Override
-        public void onDesktopSplitSelectAnimComplete(RunningTaskInfo taskInfo) {
-
-        }
-
-        @Override
-        public void stashDesktopApps(int displayId) throws RemoteException {
-            // Stashing of desktop apps not needed. Apps always launch on desktop
-        }
-
-        @Override
-        public void hideStashedDesktopApps(int displayId) throws RemoteException {
-            // Stashing of desktop apps not needed. Apps always launch on desktop
-        }
-
-        @Override
-        public void setTaskListener(IDesktopTaskListener listener) throws RemoteException {
-            // TODO(b/261234402): move visibility from sysui state to listener
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
index 517f9f2..7783113 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
@@ -16,14 +16,7 @@
 
 package com.android.wm.shell.desktopmode;
 
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
-
-import android.content.Context;
 import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import com.android.internal.protolog.common.ProtoLog;
 
 /**
  * Constants for desktop mode feature
@@ -31,13 +24,7 @@
 public class DesktopModeStatus {
 
     /**
-     * Flag to indicate whether desktop mode is available on the device
-     */
-    private static final boolean IS_SUPPORTED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
-
-    /**
-     * Flag to indicate whether desktop mode proto 2 is available on the device
+     * Flag to indicate whether desktop mode proto is available on the device
      */
     private static final boolean IS_PROTO2_ENABLED = SystemProperties.getBoolean(
             "persist.wm.debug.desktop_mode_2", false);
@@ -64,28 +51,13 @@
             "persist.wm.debug.desktop_stashing", false);
 
     /**
-     * Return {@code true} if desktop mode support is enabled
-     */
-    public static boolean isProto1Enabled() {
-        return IS_SUPPORTED;
-    }
-
-    /**
      * Return {@code true} is desktop windowing proto 2 is enabled
      */
-    public static boolean isProto2Enabled() {
+    public static boolean isEnabled() {
         return IS_PROTO2_ENABLED;
     }
 
     /**
-     * Return {@code true} if proto 1 or 2 is enabled.
-     * Can be used to guard logic that is common for both prototypes.
-     */
-    public static boolean isAnyEnabled() {
-        return isProto1Enabled() || isProto2Enabled();
-    }
-
-    /**
      * Return {@code true} if veiled resizing is active. If false, fluid resizing is used.
      */
     public static boolean isVeiledResizeEnabled() {
@@ -99,26 +71,4 @@
     public static boolean isStashingEnabled() {
         return IS_STASHING_ENABLED;
     }
-    /**
-     * Check if desktop mode is active
-     *
-     * @return {@code true} if active
-     */
-    public static boolean isActive(Context context) {
-        if (!isAnyEnabled()) {
-            return false;
-        }
-        if (isProto2Enabled()) {
-            // Desktop mode is always active in prototype 2
-            return true;
-        }
-        try {
-            int result = Settings.System.getIntForUser(context.getContentResolver(),
-                    Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
-            return result != 0;
-        } catch (Exception e) {
-            ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
-            return false;
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 0f0d572..a587bed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.view.SurfaceControl;
@@ -47,6 +48,15 @@
  * Animated visual indicator for Desktop Mode windowing transitions.
  */
 public class DesktopModeVisualIndicator {
+    public static final int INVALID_INDICATOR = -1;
+    /** Indicates impending transition into desktop mode */
+    public static final int TO_DESKTOP_INDICATOR = 1;
+    /** Indicates impending transition into fullscreen */
+    public static final int TO_FULLSCREEN_INDICATOR = 2;
+    /** Indicates impending transition into split select on the left side */
+    public static final int TO_SPLIT_LEFT_INDICATOR = 3;
+    /** Indicates impending transition into split select on the right side */
+    public static final int TO_SPLIT_RIGHT_INDICATOR = 4;
 
     private final Context mContext;
     private final DisplayController mDisplayController;
@@ -54,6 +64,7 @@
     private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer;
     private final ActivityManager.RunningTaskInfo mTaskInfo;
     private final SurfaceControl mTaskSurface;
+    private final Rect mIndicatorRange = new Rect();
     private SurfaceControl mLeash;
 
     private final SyncTransactionQueue mSyncQueue;
@@ -61,11 +72,12 @@
 
     private View mView;
     private boolean mIsFullscreen;
+    private int mType;
 
     public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue,
             ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController,
             Context context, SurfaceControl taskSurface, ShellTaskOrganizer taskOrganizer,
-            RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) {
+            RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, int type) {
         mSyncQueue = syncQueue;
         mTaskInfo = taskInfo;
         mDisplayController = displayController;
@@ -73,10 +85,64 @@
         mTaskSurface = taskSurface;
         mTaskOrganizer = taskOrganizer;
         mRootTdaOrganizer = taskDisplayAreaOrganizer;
+        mType = type;
+        defineIndicatorRange();
         createView();
     }
 
     /**
+     * If an indicator is warranted based on the input and task bounds, return the type of
+     * indicator that should be created.
+     */
+    public static int determineIndicatorType(PointF inputCoordinates, Rect taskBounds,
+            DisplayLayout layout, Context context) {
+        int transitionAreaHeight = context.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.desktop_mode_transition_area_height);
+        int transitionAreaWidth = context.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.desktop_mode_transition_area_width);
+        if (taskBounds.top <= transitionAreaHeight) return TO_FULLSCREEN_INDICATOR;
+        if (inputCoordinates.x <= transitionAreaWidth) return TO_SPLIT_LEFT_INDICATOR;
+        if (inputCoordinates.x >= layout.width() - transitionAreaWidth) {
+            return TO_SPLIT_RIGHT_INDICATOR;
+        }
+        return INVALID_INDICATOR;
+    }
+
+    /**
+     * Determine range of inputs that will keep this indicator displaying.
+     */
+    private void defineIndicatorRange() {
+        DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId);
+        int captionHeight = mContext.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.freeform_decor_caption_height);
+        int transitionAreaHeight = mContext.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.desktop_mode_transition_area_height);
+        int transitionAreaWidth = mContext.getResources().getDimensionPixelSize(
+                com.android.wm.shell.R.dimen.desktop_mode_transition_area_width);
+        switch (mType) {
+            case TO_DESKTOP_INDICATOR:
+                // TO_DESKTOP indicator is only dismissed on release; entire display is valid.
+                mIndicatorRange.set(0, 0, layout.width(), layout.height());
+                break;
+            case TO_FULLSCREEN_INDICATOR:
+                // If drag results in caption going above the top edge of the display, we still
+                // want to transition to fullscreen.
+                mIndicatorRange.set(0, -captionHeight, layout.width(), transitionAreaHeight);
+                break;
+            case TO_SPLIT_LEFT_INDICATOR:
+                mIndicatorRange.set(0, transitionAreaHeight, transitionAreaWidth, layout.height());
+                break;
+            case TO_SPLIT_RIGHT_INDICATOR:
+                mIndicatorRange.set(layout.width() - transitionAreaWidth, transitionAreaHeight,
+                        layout.width(), layout.height());
+                break;
+            default:
+                break;
+        }
+    }
+
+
+    /**
      * Create a fullscreen indicator with no animation
      */
     private void createView() {
@@ -85,11 +151,30 @@
         final DisplayMetrics metrics = resources.getDisplayMetrics();
         final int screenWidth = metrics.widthPixels;
         final int screenHeight = metrics.heightPixels;
+
         mView = new View(mContext);
         final SurfaceControl.Builder builder = new SurfaceControl.Builder();
         mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder);
+        String description;
+        switch (mType) {
+            case TO_DESKTOP_INDICATOR:
+                description = "Desktop indicator";
+                break;
+            case TO_FULLSCREEN_INDICATOR:
+                description = "Fullscreen indicator";
+                break;
+            case TO_SPLIT_LEFT_INDICATOR:
+                description = "Split Left indicator";
+                break;
+            case TO_SPLIT_RIGHT_INDICATOR:
+                description = "Split Right indicator";
+                break;
+            default:
+                description = "Invalid indicator";
+                break;
+        }
         mLeash = builder
-                .setName("Fullscreen Indicator")
+                .setName(description)
                 .setContainerLayer()
                 .build();
         t.show(mLeash);
@@ -97,14 +182,14 @@
                 new WindowManager.LayoutParams(screenWidth, screenHeight,
                         WindowManager.LayoutParams.TYPE_APPLICATION,
                         WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
-        lp.setTitle("Fullscreen indicator for Task=" + mTaskInfo.taskId);
+        lp.setTitle(description + " for Task=" + mTaskInfo.taskId);
         lp.setTrustedOverlay();
         final WindowlessWindowManager windowManager = new WindowlessWindowManager(
                 mTaskInfo.configuration, mLeash,
                 null /* hostInputToken */);
         mViewHost = new SurfaceControlViewHost(mContext,
                 mDisplayController.getDisplay(mTaskInfo.displayId), windowManager,
-                "FullscreenVisualIndicator");
+                "DesktopModeVisualIndicator");
         mViewHost.setView(mView, lp);
         // We want this indicator to be behind the dragged task, but in front of all others.
         t.setRelativeLayer(mLeash, mTaskSurface, -1);
@@ -116,24 +201,13 @@
     }
 
     /**
-     * Create fullscreen indicator and fades it in.
+     * Create an indicator. Animator fades it in while expanding the bounds outwards.
      */
-    public void createFullscreenIndicator() {
-        mIsFullscreen = true;
-        mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background);
-        final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimator(
-                mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId));
-        animator.start();
-    }
-
-    /**
-     * Create a fullscreen indicator. Animator fades it in while expanding the bounds outwards.
-     */
-    public void createFullscreenIndicatorWithAnimatedBounds() {
-        mIsFullscreen = true;
+    public void createIndicatorWithAnimatedBounds() {
+        mIsFullscreen = mType == TO_FULLSCREEN_INDICATOR;
         mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background);
         final VisualIndicatorAnimator animator = VisualIndicatorAnimator
-                .toFullscreenAnimatorWithAnimatedBounds(mView,
+                .animateBounds(mView, mType,
                         mDisplayController.getDisplayLayout(mTaskInfo.displayId));
         animator.start();
     }
@@ -143,6 +217,7 @@
      */
     public void transitionFullscreenIndicatorToFreeform() {
         mIsFullscreen = false;
+        mType = TO_DESKTOP_INDICATOR;
         final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFreeformAnimator(
                 mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId));
         animator.start();
@@ -153,6 +228,7 @@
      */
     public void transitionFreeformIndicatorToFullscreen() {
         mIsFullscreen = true;
+        mType = TO_FULLSCREEN_INDICATOR;
         final VisualIndicatorAnimator animator =
                 VisualIndicatorAnimator.toFullscreenAnimatorWithAnimatedBounds(
                 mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId));
@@ -160,6 +236,14 @@
     }
 
     /**
+     * Determine if a MotionEvent is in the same range that enabled the indicator.
+     * Used to dismiss the indicator when a transition will no longer result from releasing.
+     */
+    public boolean eventOutsideRange(float x, float y) {
+        return !mIndicatorRange.contains((int) x, (int) y);
+    }
+
+    /**
      * Release the indicator and its components when it is no longer needed.
      */
     public void releaseVisualIndicator(SurfaceControl.Transaction t) {
@@ -210,23 +294,6 @@
          * @param view the view for this indicator
          * @param displayLayout information about the display the transitioning task is currently on
          */
-        public static VisualIndicatorAnimator toFullscreenAnimator(@NonNull View view,
-                @NonNull DisplayLayout displayLayout) {
-            final Rect bounds = getMaxBounds(displayLayout);
-            final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
-                    view, bounds, bounds);
-            animator.setInterpolator(new DecelerateInterpolator());
-            setupIndicatorAnimation(animator);
-            return animator;
-        }
-
-
-        /**
-         * Create animator for visual indicator of fullscreen transition
-         *
-         * @param view the view for this indicator
-         * @param displayLayout information about the display the transitioning task is currently on
-         */
         public static VisualIndicatorAnimator toFullscreenAnimatorWithAnimatedBounds(
                 @NonNull View view, @NonNull DisplayLayout displayLayout) {
             final int padding = displayLayout.stableInsets().top;
@@ -235,7 +302,37 @@
             view.getBackground().setBounds(startBounds);
 
             final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
-                    view, startBounds, getMaxBounds(displayLayout));
+                    view, startBounds, getMaxBounds(startBounds));
+            animator.setInterpolator(new DecelerateInterpolator());
+            setupIndicatorAnimation(animator);
+            return animator;
+        }
+
+        public static VisualIndicatorAnimator animateBounds(
+                @NonNull View view, int type, @NonNull DisplayLayout displayLayout) {
+            final int padding = displayLayout.stableInsets().top;
+            Rect startBounds = new Rect();
+            switch (type) {
+                case TO_FULLSCREEN_INDICATOR:
+                    startBounds.set(padding, padding,
+                            displayLayout.width() - padding,
+                            displayLayout.height() - padding);
+                    break;
+                case TO_SPLIT_LEFT_INDICATOR:
+                    startBounds.set(padding, padding,
+                            displayLayout.width() / 2 - padding,
+                            displayLayout.height() - padding);
+                    break;
+                case TO_SPLIT_RIGHT_INDICATOR:
+                    startBounds.set(displayLayout.width() / 2 + padding, padding,
+                            displayLayout.width() - padding,
+                            displayLayout.height() - padding);
+                    break;
+            }
+            view.getBackground().setBounds(startBounds);
+
+            final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
+                    view, startBounds, getMaxBounds(startBounds));
             animator.setInterpolator(new DecelerateInterpolator());
             setupIndicatorAnimation(animator);
             return animator;
@@ -252,12 +349,13 @@
             final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE;
             final int width = displayLayout.width();
             final int height = displayLayout.height();
+            Rect startBounds = new Rect(0, 0, width, height);
             Rect endBounds = new Rect((int) (adjustmentPercentage * width / 2),
                     (int) (adjustmentPercentage * height / 2),
                     (int) (displayLayout.width() - (adjustmentPercentage * width / 2)),
                     (int) (displayLayout.height() - (adjustmentPercentage * height / 2)));
             final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
-                    view, getMaxBounds(displayLayout), endBounds);
+                    view, startBounds, endBounds);
             animator.setInterpolator(new DecelerateInterpolator());
             setupIndicatorAnimation(animator);
             return animator;
@@ -310,21 +408,17 @@
         }
 
         /**
-         * Return the max bounds of a fullscreen indicator
+         * Return the max bounds of a visual indicator
          */
-        private static Rect getMaxBounds(@NonNull DisplayLayout displayLayout) {
-            final int padding = displayLayout.stableInsets().top;
-            final int width = displayLayout.width() - 2 * padding;
-            final int height = displayLayout.height() - 2 * padding;
-            Rect endBounds = new Rect((int) (padding
-                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * width)),
-                    (int) (padding
-                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * height)),
-                    (int) (displayLayout.width() - padding
-                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * width)),
-                    (int) (displayLayout.height() - padding
-                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * height)));
-            return endBounds;
+        private static Rect getMaxBounds(Rect startBounds) {
+            return new Rect((int) (startBounds.left
+                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.width())),
+                    (int) (startBounds.top
+                            - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.height())),
+                    (int) (startBounds.right
+                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.width())),
+                    (int) (startBounds.bottom
+                            + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * startBounds.height())));
         }
     }
 }
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 4740a9d..b918c83 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
@@ -29,6 +29,7 @@
 import android.content.Context
 import android.content.res.TypedArray
 import android.graphics.Point
+import android.graphics.PointF
 import android.graphics.Rect
 import android.graphics.Region
 import android.os.IBinder
@@ -55,7 +56,10 @@
 import com.android.wm.shell.common.SyncTransactionQueue
 import com.android.wm.shell.common.annotations.ExternalThread
 import com.android.wm.shell.common.annotations.ShellMainThread
+import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
+import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.splitscreen.SplitScreenController
 import com.android.wm.shell.sysui.ShellCommandHandler
@@ -108,12 +112,17 @@
                 com.android.wm.shell.R.dimen.desktop_mode_transition_area_height
         )
 
+    private val transitionAreaWidth
+        get() = context.resources.getDimensionPixelSize(
+            com.android.wm.shell.R.dimen.desktop_mode_transition_area_width
+        )
+
     // This is public to avoid cyclic dependency; it is set by SplitScreenController
     lateinit var splitScreenController: SplitScreenController
 
     init {
         desktopMode = DesktopModeImpl()
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             shellInit.addInitCallback({ onInit() }, this)
         }
     }
@@ -805,7 +814,8 @@
         ) {
             val wct = WindowContainerTransaction()
             addMoveToSplitChanges(wct, taskInfo)
-            splitScreenController.requestEnterSplitSelect(taskInfo, wct)
+            splitScreenController.requestEnterSplitSelect(taskInfo, wct,
+                SPLIT_POSITION_BOTTOM_OR_RIGHT, taskInfo.configuration.windowConfiguration.bounds)
         }
     }
 
@@ -829,25 +839,36 @@
 
     /**
      * Perform checks required on drag move. Create/release fullscreen indicator as needed.
+     * Different sources for x and y coordinates are used due to different needs for each:
+     * We want split transitions to be based on input coordinates but fullscreen transition
+     * to be based on task edge coordinate.
      *
      * @param taskInfo the task being dragged.
      * @param taskSurface SurfaceControl of dragged task.
-     * @param y coordinate of dragged task. Used for checks against status bar height.
+     * @param inputCoordinate coordinates of input. Used for checks against left/right edge of screen.
+     * @param taskBounds bounds of dragged task. Used for checks against status bar height.
      */
     fun onDragPositioningMove(
-            taskInfo: RunningTaskInfo,
-            taskSurface: SurfaceControl,
-            y: Float
+        taskInfo: RunningTaskInfo,
+        taskSurface: SurfaceControl,
+        inputCoordinate: PointF,
+        taskBounds: Rect
     ) {
-        if (taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
-            if (y <= transitionAreaHeight && visualIndicator == null) {
-                visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
-                        displayController, context, taskSurface, shellTaskOrganizer,
-                        rootTaskDisplayAreaOrganizer)
-                visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
-            } else if (y > transitionAreaHeight && visualIndicator != null) {
-                releaseVisualIndicator()
-            }
+        val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
+        if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return
+        var type = DesktopModeVisualIndicator.determineIndicatorType(inputCoordinate,
+            taskBounds, displayLayout, context)
+        if (type != DesktopModeVisualIndicator.INVALID_INDICATOR && visualIndicator == null) {
+            visualIndicator = DesktopModeVisualIndicator(
+                syncQueue, taskInfo,
+                displayController, context, taskSurface, shellTaskOrganizer,
+                rootTaskDisplayAreaOrganizer, type)
+            visualIndicator?.createIndicatorWithAnimatedBounds()
+            return
+        }
+        if (visualIndicator?.eventOutsideRange(inputCoordinate.x,
+                taskBounds.top.toFloat()) == true) {
+            releaseVisualIndicator()
         }
     }
 
@@ -856,19 +877,39 @@
      *
      * @param taskInfo the task being dragged.
      * @param position position of surface when drag ends.
-     * @param y the Y position of the top edge of the task
+     * @param inputCoordinate the coordinates of the motion event
+     * @param taskBounds the updated bounds of the task being dragged.
      * @param windowDecor the window decoration for the task being dragged
      */
     fun onDragPositioningEnd(
-            taskInfo: RunningTaskInfo,
-            position: Point,
-            y: Float,
-            windowDecor: DesktopModeWindowDecoration
+        taskInfo: RunningTaskInfo,
+        position: Point,
+        inputCoordinate: PointF,
+        taskBounds: Rect,
+        windowDecor: DesktopModeWindowDecoration
     ) {
-        if (y <= transitionAreaHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+        if (taskInfo.configuration.windowConfiguration.windowingMode != WINDOWING_MODE_FREEFORM) {
+            return
+        }
+        if (taskBounds.top <= transitionAreaHeight) {
             windowDecor.incrementRelayoutBlock()
             moveToFullscreenWithAnimation(taskInfo, position)
         }
+        if (inputCoordinate.x <= transitionAreaWidth) {
+            releaseVisualIndicator()
+            var wct = WindowContainerTransaction()
+            addMoveToSplitChanges(wct, taskInfo)
+            splitScreenController.requestEnterSplitSelect(taskInfo, wct,
+                SPLIT_POSITION_TOP_OR_LEFT, taskBounds)
+        }
+        if (inputCoordinate.x >= (displayController.getDisplayLayout(taskInfo.displayId)?.width()
+            ?.minus(transitionAreaWidth) ?: return)) {
+            releaseVisualIndicator()
+            var wct = WindowContainerTransaction()
+            addMoveToSplitChanges(wct, taskInfo)
+            splitScreenController.requestEnterSplitSelect(taskInfo, wct,
+                SPLIT_POSITION_BOTTOM_OR_RIGHT, taskBounds)
+        }
     }
 
     /**
@@ -892,8 +933,8 @@
         if (visualIndicator == null) {
             visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
                     displayController, context, taskSurface, shellTaskOrganizer,
-                    rootTaskDisplayAreaOrganizer)
-            visualIndicator?.createFullscreenIndicator()
+                    rootTaskDisplayAreaOrganizer, TO_DESKTOP_INDICATOR)
+            visualIndicator?.createIndicatorWithAnimatedBounds()
         }
         val indicator = visualIndicator ?: return
         if (y >= getFreeformTransitionStatusBarDragThreshold(taskInfo)) {
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 22541bbd..a80241e 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
@@ -68,7 +68,7 @@
 
     private void onInit() {
         mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FREEFORM);
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mShellTaskOrganizer.addFocusListener(this);
         }
     }
@@ -90,7 +90,7 @@
             t.apply();
         }
 
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
                 if (taskInfo.isVisible) {
@@ -111,7 +111,7 @@
                 taskInfo.taskId);
         mTasks.remove(taskInfo.taskId);
 
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 repository.removeFreeformTask(taskInfo.taskId);
                 if (repository.removeActiveTask(taskInfo.taskId)) {
@@ -135,7 +135,7 @@
                 taskInfo.taskId);
         mWindowDecorationViewModel.onTaskInfoChanged(taskInfo);
         state.mTaskInfo = taskInfo;
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 if (taskInfo.isVisible) {
                     if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
@@ -154,7 +154,7 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG,
                 "Freeform Task Focus Changed: #%d focused=%b",
                 taskInfo.taskId, taskInfo.isFocused);
-        if (DesktopModeStatus.isAnyEnabled() && taskInfo.isFocused) {
+        if (DesktopModeStatus.isEnabled() && taskInfo.isFocused) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
             });
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e3922d6..018d674 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -1059,7 +1059,21 @@
     private void resetPrevPip(@NonNull TransitionInfo.Change prevPipTaskChange,
             @NonNull SurfaceControl.Transaction startTransaction) {
         final SurfaceControl leash = prevPipTaskChange.getLeash();
-        startTransaction.remove(leash);
+        final Rect bounds = prevPipTaskChange.getEndAbsBounds();
+        final Point offset = prevPipTaskChange.getEndRelOffset();
+        bounds.offset(-offset.x, -offset.y);
+
+        startTransaction.setWindowCrop(leash, null);
+        startTransaction.setMatrix(leash, 1, 0, 0, 1);
+        startTransaction.setCornerRadius(leash, 0);
+        startTransaction.setPosition(leash, bounds.left, bounds.top);
+
+        if (mHasFadeOut && prevPipTaskChange.getTaskInfo().isVisible()) {
+            if (mPipAnimationController.getCurrentAnimator() != null) {
+                mPipAnimationController.getCurrentAnimator().cancel();
+            }
+            startTransaction.setAlpha(leash, 1);
+        }
 
         mHasFadeOut = false;
         mCurrentPipTaskToken = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
index ec09827..6dabb3b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/OWNERS
@@ -1,3 +1,4 @@
 # WM shell sub-module pip owner
 hwwang@google.com
 mateuszc@google.com
+gabiyev@google.com
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 ac142e9..94e1b33 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
@@ -340,7 +340,7 @@
                 continue;
             }
 
-            if (DesktopModeStatus.isProto2Enabled() && mDesktopModeTaskRepository.isPresent()
+            if (DesktopModeStatus.isEnabled() && mDesktopModeTaskRepository.isPresent()
                     && mDesktopModeTaskRepository.get().isActiveTask(taskInfo.taskId)) {
                 // Freeform tasks will be added as a separate entry
                 freeformTasks.add(taskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitSelectListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitSelectListener.aidl
index 7171da5..a25f391 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitSelectListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitSelectListener.aidl
@@ -17,7 +17,7 @@
 package com.android.wm.shell.splitscreen;
 
 import android.app.ActivityManager.RunningTaskInfo;
-
+import android.graphics.Rect;
 /**
  * Listener interface that Launcher attaches to SystemUI to get split-select callbacks.
  */
@@ -25,5 +25,5 @@
     /**
      * Called when a task requests to enter split select
      */
-    boolean onRequestSplitSelect(in RunningTaskInfo taskInfo);
+    boolean onRequestSplitSelect(in RunningTaskInfo taskInfo, int splitPosition, in Rect taskBounds);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index f20fe0b..ad40493 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -66,7 +66,8 @@
 
     /** Callback interface for listening to requests to enter split select */
     interface SplitSelectListener {
-        default boolean onRequestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo) {
+        default boolean onRequestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
+                int splitPosition, Rect taskBounds) {
             return false;
         }
     }
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 210bf68..f90ee58 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
@@ -507,10 +507,12 @@
      * Move a task to split select
      * @param taskInfo the task being moved to split select
      * @param wct transaction to apply if this is a valid request
+     * @param splitPosition the split position this task should move to
+     * @param taskBounds current freeform bounds of the task entering split
      */
     public void requestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
-            WindowContainerTransaction wct) {
-        mStageCoordinator.requestEnterSplitSelect(taskInfo, wct);
+            WindowContainerTransaction wct, int splitPosition, Rect taskBounds) {
+        mStageCoordinator.requestEnterSplitSelect(taskInfo, wct, splitPosition, taskBounds);
     }
 
     public void startTask(int taskId, @SplitPosition int position, @Nullable Bundle options) {
@@ -1135,9 +1137,11 @@
                 new SplitScreen.SplitSelectListener() {
                     @Override
                     public boolean onRequestEnterSplitSelect(
-                            ActivityManager.RunningTaskInfo taskInfo) {
+                            ActivityManager.RunningTaskInfo taskInfo, int splitPosition,
+                            Rect taskBounds) {
                         AtomicBoolean result = new AtomicBoolean(false);
-                        mSelectListener.call(l -> result.set(l.onRequestSplitSelect(taskInfo)));
+                        mSelectListener.call(l -> result.set(l.onRequestSplitSelect(taskInfo,
+                                splitPosition, taskBounds)));
                         return result.get();
                     }
                 };
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 6970068..94fa485 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
@@ -228,6 +228,15 @@
     private final Toast mSplitUnsupportedToast;
     private SplitRequest mSplitRequest;
 
+    /**
+     * Since StageCoordinator only coordinates MainStage and SideStage, it shouldn't support
+     * CompatUI layouts. CompatUI is handled separately by MainStage and SideStage.
+     */
+    @Override
+    public boolean supportCompatUI() {
+        return false;
+    }
+
     class SplitRequest {
         @SplitPosition
         int mActivatePosition;
@@ -466,10 +475,11 @@
     }
 
     void requestEnterSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
-            WindowContainerTransaction wct) {
+            WindowContainerTransaction wct, int splitPosition, Rect taskBounds) {
         boolean enteredSplitSelect = false;
         for (SplitScreen.SplitSelectListener listener : mSelectListeners) {
-            enteredSplitSelect |= listener.onRequestEnterSplitSelect(taskInfo);
+            enteredSplitSelect |= listener.onRequestEnterSplitSelect(taskInfo, splitPosition,
+                    taskBounds);
         }
         if (enteredSplitSelect) mTaskOrganizer.applyTransaction(wct);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 986560b..87ceaa4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -43,7 +43,6 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.split.SplitScreenUtils;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
@@ -71,7 +70,6 @@
     private RecentsTransitionHandler mRecentsHandler;
     private StageCoordinator mSplitHandler;
     private final KeyguardTransitionHandler mKeyguardHandler;
-    private DesktopModeController mDesktopModeController;
     private DesktopTasksController mDesktopTasksController;
     private UnfoldTransitionHandler mUnfoldHandler;
 
@@ -141,7 +139,6 @@
             @Nullable PipTransitionController pipTransitionController,
             Optional<RecentsTransitionHandler> recentsHandlerOptional,
             KeyguardTransitionHandler keyguardHandler,
-            Optional<DesktopModeController> desktopModeControllerOptional,
             Optional<DesktopTasksController> desktopTasksControllerOptional,
             Optional<UnfoldTransitionHandler> unfoldHandler) {
         mPlayer = player;
@@ -161,7 +158,6 @@
                 if (mRecentsHandler != null) {
                     mRecentsHandler.addMixer(this);
                 }
-                mDesktopModeController = desktopModeControllerOptional.orElse(null);
                 mDesktopTasksController = desktopTasksControllerOptional.orElse(null);
                 mUnfoldHandler = unfoldHandler.orElse(null);
             }, this);
@@ -244,7 +240,7 @@
     @Override
     public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
         if (mRecentsHandler != null && (mSplitHandler.isSplitScreenVisible()
-                || DesktopModeStatus.isActive(mPlayer.getContext()))) {
+                || DesktopModeStatus.isEnabled())) {
             return this;
         }
         return null;
@@ -259,7 +255,7 @@
                     MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
             mixed.mLeftoversHandler = mRecentsHandler;
             mActiveTransitions.add(mixed);
-        } else if (DesktopModeStatus.isActive(mPlayer.getContext())) {
+        } else if (DesktopModeStatus.isEnabled()) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
                     + "desktop mode is active, so treat it as Mixed.");
             final MixedTransition mixed = new MixedTransition(
@@ -666,11 +662,6 @@
         if (!consumed) {
             return false;
         }
-        //Sync desktop mode state (proto 1)
-        if (mDesktopModeController != null) {
-            mDesktopModeController.syncSurfaceState(info, finishTransaction);
-            return true;
-        }
         //Sync desktop mode state (proto 2)
         if (mDesktopTasksController != null) {
             mDesktopTasksController.syncSurfaceState(info, finishTransaction);
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 ce81910..c189731 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
@@ -64,7 +64,8 @@
             Handler handler,
             Choreographer choreographer,
             SyncTransactionQueue syncQueue) {
-        super(context, displayController, taskOrganizer, taskInfo, taskSurface);
+        super(context, displayController, taskOrganizer, taskInfo, taskSurface,
+                taskInfo.getConfiguration());
 
         mHandler = handler;
         mChoreographer = choreographer;
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 026e973..abd2ad4 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
@@ -36,6 +36,7 @@
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.input.InputManager;
@@ -68,7 +69,6 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
@@ -101,7 +101,6 @@
     private final Choreographer mMainChoreographer;
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
-    private final Optional<DesktopModeController> mDesktopModeController;
     private final Optional<DesktopTasksController> mDesktopTasksController;
     private boolean mTransitionDragActive;
 
@@ -134,7 +133,6 @@
             ShellController shellController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
     ) {
@@ -148,7 +146,6 @@
                 shellController,
                 syncQueue,
                 transitions,
-                desktopModeController,
                 desktopTasksController,
                 new DesktopModeWindowDecoration.Factory(),
                 new InputMonitorFactory(),
@@ -168,7 +165,6 @@
             ShellController shellController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
             InputMonitorFactory inputMonitorFactory,
@@ -184,7 +180,6 @@
         mDisplayController = displayController;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
-        mDesktopModeController = desktopModeController;
         mDesktopTasksController = desktopTasksController;
 
         mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
@@ -213,9 +208,8 @@
             public void onTaskStageChanged(int taskId, int stage, boolean visible) {
                 if (visible) {
                     DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
-                    if (decor != null && DesktopModeStatus.isActive(mContext)
+                    if (decor != null && DesktopModeStatus.isEnabled()
                             && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-                        mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
                         mDesktopTasksController.ifPresent(c -> c.moveToSplit(decor.mTaskInfo));
                     }
                 }
@@ -375,7 +369,6 @@
                     decoration.closeHandleMenu();
                 }
             } else if (id == R.id.desktop_button) {
-                mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
                 if (mDesktopTasksController.isPresent()) {
                     final WindowContainerTransaction wct = new WindowContainerTransaction();
                     // App sometimes draws before the insets from WindowDecoration#relayout have
@@ -386,7 +379,6 @@
                 }
                 decoration.closeHandleMenu();
             } else if (id == R.id.fullscreen_button) {
-                mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
                 mDesktopTasksController.ifPresent(c -> c.moveToFullscreen(mTaskId));
                 decoration.closeHandleMenu();
             } else if (id == R.id.split_screen_button) {
@@ -464,7 +456,6 @@
         private void moveTaskToFront(RunningTaskInfo taskInfo) {
             if (!taskInfo.isFocused) {
                 mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo));
-                mDesktopModeController.ifPresent(c -> c.moveTaskToFront(taskInfo));
             }
         }
 
@@ -475,15 +466,10 @@
         @Override
         public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
             final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-            if (DesktopModeStatus.isProto2Enabled()
+            if (DesktopModeStatus.isEnabled()
                     && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                 return false;
             }
-            if (DesktopModeStatus.isProto1Enabled() && mDesktopModeController.isPresent()
-                    && mDesktopModeController.get().getDisplayAreaWindowingMode(taskInfo.displayId)
-                    == WINDOWING_MODE_FULLSCREEN) {
-                return false;
-            }
             if (mGestureDetector.onTouchEvent(e)) {
                 return true;
             }
@@ -507,7 +493,9 @@
                     final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningMove(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
                     mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo,
-                            decoration.mTaskSurface, newTaskBounds.top));
+                            decoration.mTaskSurface,
+                            new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)),
+                            newTaskBounds));
                     mIsDragging = true;
                     mShouldClick = false;
                     return true;
@@ -536,7 +524,9 @@
                     final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
                     mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
-                            position, newTaskBounds.top, mWindowDecorByTaskId.get(mTaskId)));
+                            position,
+                            new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)),
+                            newTaskBounds, mWindowDecorByTaskId.get(mTaskId)));
                     mIsDragging = false;
                     return true;
                 }
@@ -629,7 +619,7 @@
      */
     private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
         final DesktopModeWindowDecoration relevantDecor = getRelevantWindowDecor(ev);
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             if (relevantDecor == null
                     || relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM
                     || mTransitionDragActive) {
@@ -638,14 +628,10 @@
         }
         handleEventOutsideFocusedCaption(ev, relevantDecor);
         // Prevent status bar from reacting to a caption drag.
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             if (mTransitionDragActive) {
                 inputMonitor.pilferPointers();
             }
-        } else if (DesktopModeStatus.isProto1Enabled()) {
-            if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) {
-                inputMonitor.pilferPointers();
-            }
         }
     }
 
@@ -678,7 +664,7 @@
                     mDragToDesktopAnimationStartBounds.set(
                             relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
                     boolean dragFromStatusBarAllowed = false;
-                    if (DesktopModeStatus.isProto2Enabled()) {
+                    if (DesktopModeStatus.isEnabled()) {
                         // In proto2 any full screen or multi-window task can be dragged to
                         // freeform.
                         final int windowingMode = relevantDecor.mTaskInfo.getWindowingMode();
@@ -703,10 +689,8 @@
                     final int statusBarHeight = getStatusBarHeight(
                             relevantDecor.mTaskInfo.displayId);
                     if (ev.getY() > 2 * statusBarHeight) {
-                        if (DesktopModeStatus.isProto2Enabled()) {
+                        if (DesktopModeStatus.isEnabled()) {
                             animateToDesktop(relevantDecor, ev);
-                        } else if (DesktopModeStatus.isProto1Enabled()) {
-                            mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
                         }
                         mMoveToDesktopAnimator = null;
                         return;
@@ -897,7 +881,7 @@
                 && taskInfo.isFocused) {
             return false;
         }
-        return DesktopModeStatus.isProto2Enabled()
+        return DesktopModeStatus.isEnabled()
                 && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
                 && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
                 && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop()
@@ -979,13 +963,11 @@
 
         @Override
         public void onTaskCornersChanged(int taskId, Region corner) {
-            mDesktopModeController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
             mDesktopTasksController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
         }
 
         @Override
         public void onTaskCornersRemoved(int taskId) {
-            mDesktopModeController.ifPresent(d -> d.removeCornersForTask(taskId));
             mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId));
         }
     }
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 a75dce2..e954f3b 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
@@ -104,11 +104,12 @@
             ShellTaskOrganizer taskOrganizer,
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
+            Configuration windowDecorConfig,
             Handler handler,
             Choreographer choreographer,
             SyncTransactionQueue syncQueue,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
-        super(context, displayController, taskOrganizer, taskInfo, taskSurface);
+        super(context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig);
 
         mHandler = handler;
         mChoreographer = choreographer;
@@ -118,17 +119,6 @@
         loadAppInfo();
     }
 
-    @Override
-    protected Configuration getConfigurationWithOverrides(
-            ActivityManager.RunningTaskInfo taskInfo) {
-        Configuration configuration = taskInfo.getConfiguration();
-        if (DesktopTasksController.isDesktopDensityOverrideSet()) {
-            // Density is overridden for desktop tasks. Keep system density for window decoration.
-            configuration.densityDpi = mContext.getResources().getConfiguration().densityDpi;
-        }
-        return configuration;
-    }
-
     void setCaptionListeners(
             View.OnClickListener onCaptionButtonClickListener,
             View.OnTouchListener onCaptionTouchListener,
@@ -194,6 +184,10 @@
         mRelayoutParams.mShadowRadiusId = shadowRadiusID;
         mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
 
+        mRelayoutParams.mWindowDecorConfig = DesktopTasksController.isDesktopDensityOverrideSet()
+                ? mContext.getResources().getConfiguration() // Use system context
+                : mTaskInfo.configuration; // Use task configuration
+
         mRelayoutParams.mCornerRadius =
                 (int) ScreenDecorationsUtils.getWindowCornerRadius(mContext);
         relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
@@ -428,7 +422,7 @@
                 .setOnTouchListener(mOnCaptionTouchListener)
                 .setLayoutId(mRelayoutParams.mLayoutResId)
                 .setCaptionPosition(mRelayoutParams.mCaptionX, mRelayoutParams.mCaptionY)
-                .setWindowingButtonsVisible(DesktopModeStatus.isProto2Enabled())
+                .setWindowingButtonsVisible(DesktopModeStatus.isEnabled())
                 .build();
         mHandleMenu.show();
     }
@@ -549,9 +543,6 @@
     }
 
     private int getDesktopModeWindowDecorLayoutId(int windowingMode) {
-        if (DesktopModeStatus.isProto1Enabled()) {
-            return R.layout.desktop_mode_app_controls_window_decor;
-        }
         return windowingMode == WINDOWING_MODE_FREEFORM
                 ? R.layout.desktop_mode_app_controls_window_decor
                 : R.layout.desktop_mode_focused_window_decor;
@@ -617,12 +608,17 @@
                 Choreographer choreographer,
                 SyncTransactionQueue syncQueue,
                 RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+            final Configuration windowDecorConfig =
+                    DesktopTasksController.isDesktopDensityOverrideSet()
+                    ? context.getResources().getConfiguration() // Use system context
+                    : taskInfo.configuration; // Use task configuration
             return new DesktopModeWindowDecoration(
                     context,
                     displayController,
                     taskOrganizer,
                     taskInfo,
                     taskSurface,
+                    windowDecorConfig,
                     handler,
                     choreographer,
                     syncQueue,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
index ac4a597..42b1240 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -186,7 +186,12 @@
         // More Actions pill setup.
         final View moreActionsPillView = mMoreActionsPill.mWindowViewHost.getView();
         final Button closeBtn = moreActionsPillView.findViewById(R.id.close_button);
-        closeBtn.setOnClickListener(mOnClickListener);
+        if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+            closeBtn.setVisibility(View.GONE);
+        } else {
+            closeBtn.setVisibility(View.VISIBLE);
+            closeBtn.setOnClickListener(mOnClickListener);
+        }
         final Button selectBtn = moreActionsPillView.findViewById(R.id.select_button);
         selectBtn.setOnClickListener(mOnClickListener);
     }
@@ -228,7 +233,6 @@
 
     /**
      * Update pill layout, in case task changes have caused positioning to change.
-     * @param t
      */
     void relayout(SurfaceControl.Transaction t) {
         if (mAppInfoPill != null) {
@@ -236,7 +240,7 @@
             t.setPosition(mAppInfoPill.mWindowSurface,
                     mAppInfoPillPosition.x, mAppInfoPillPosition.y);
             // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
-            final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
+            final boolean shouldShowWindowingPill = DesktopModeStatus.isEnabled();
             if (shouldShowWindowingPill) {
                 t.setPosition(mWindowingPill.mWindowSurface,
                         mWindowingPillPosition.x, mWindowingPillPosition.y);
@@ -245,10 +249,12 @@
                     mMoreActionsPillPosition.x, mMoreActionsPillPosition.y);
         }
     }
+
     /**
      * Check a passed MotionEvent if a click has occurred on any button on this caption
      * Note this should only be called when a regular onClick is not possible
      * (i.e. the button was clicked through status bar layer)
+     *
      * @param ev the MotionEvent to compare against.
      */
     void checkClickEvent(MotionEvent ev) {
@@ -267,6 +273,7 @@
      * A valid menu input is one of the following:
      * An input that happens in the menu views.
      * Any input before the views have been laid out.
+     *
      * @param inputPoint the input to compare against.
      */
     boolean isValidMenuInput(PointF inputPoint) {
@@ -297,7 +304,6 @@
 
     /**
      * Check if the views for handle menu can be seen.
-     * @return
      */
     private boolean viewsLaidOut() {
         return mAppInfoPill.mWindowViewHost.getView().isLaidOut();
@@ -318,8 +324,7 @@
                 R.dimen.desktop_mode_handle_menu_app_info_pill_height);
         mWindowingPillHeight = loadDimensionPixelSize(resources,
                 R.dimen.desktop_mode_handle_menu_windowing_pill_height);
-        mMoreActionsPillHeight = loadDimensionPixelSize(resources,
-                R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
+        mMoreActionsPillHeight = shouldShowCloseButton(resources);
         mShadowRadius = loadDimensionPixelSize(resources,
                 R.dimen.desktop_mode_handle_menu_shadow_radius);
         mCornerRadius = loadDimensionPixelSize(resources,
@@ -333,6 +338,14 @@
         return resources.getDimensionPixelSize(resourceId);
     }
 
+    private int shouldShowCloseButton(Resources resources) {
+        return (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM)
+                ? loadDimensionPixelSize(resources,
+                R.dimen.desktop_mode_handle_menu_more_actions_pill_freeform_height)
+                : loadDimensionPixelSize(resources,
+                        R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
+    }
+
     void close() {
         mAppInfoPill.releaseView();
         mAppInfoPill = null;
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 0b0d9d5..8d76fc6 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
@@ -115,6 +115,7 @@
     SurfaceControl mCaptionContainerSurface;
     private WindowlessWindowManager mCaptionWindowManager;
     private SurfaceControlViewHost mViewHost;
+    private Configuration mWindowDecorConfig;
 
     private final Binder mOwner = new Binder();
     private final Rect mCaptionInsetsRect = new Rect();
@@ -125,8 +126,9 @@
             DisplayController displayController,
             ShellTaskOrganizer taskOrganizer,
             RunningTaskInfo taskInfo,
-            SurfaceControl taskSurface) {
-        this(context, displayController, taskOrganizer, taskInfo, taskSurface,
+            SurfaceControl taskSurface,
+            Configuration windowDecorConfig) {
+        this(context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig,
                 SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
                 WindowContainerTransaction::new, new SurfaceControlViewHostFactory() {});
     }
@@ -137,6 +139,7 @@
             ShellTaskOrganizer taskOrganizer,
             RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
+            Configuration windowDecorConfig,
             Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
             Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
             Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
@@ -152,17 +155,8 @@
         mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
 
         mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
-        mDecorWindowContext = mContext.createConfigurationContext(
-                getConfigurationWithOverrides(mTaskInfo));
-    }
-
-    /**
-     * Get {@link Configuration} from supplied {@link RunningTaskInfo}.
-     *
-     * Allows values to be overridden before returning the configuration.
-     */
-    protected Configuration getConfigurationWithOverrides(RunningTaskInfo taskInfo) {
-        return taskInfo.getConfiguration();
+        mWindowDecorConfig = windowDecorConfig;
+        mDecorWindowContext = mContext.createConfigurationContext(mWindowDecorConfig);
     }
 
     /**
@@ -179,7 +173,6 @@
             RelayoutResult<T> outResult) {
         outResult.reset();
 
-        final Configuration oldTaskConfig = mTaskInfo.getConfiguration();
         if (params.mRunningTaskInfo != null) {
             mTaskInfo = params.mRunningTaskInfo;
         }
@@ -198,8 +191,11 @@
 
         outResult.mRootView = rootView;
         rootView = null; // Clear it just in case we use it accidentally
-        final Configuration taskConfig = getConfigurationWithOverrides(mTaskInfo);
-        if (oldTaskConfig.densityDpi != taskConfig.densityDpi
+
+        final int oldDensityDpi = mWindowDecorConfig.densityDpi;
+        mWindowDecorConfig = params.mWindowDecorConfig != null ? params.mWindowDecorConfig
+                : mTaskInfo.getConfiguration();
+        if (oldDensityDpi != mWindowDecorConfig.densityDpi
                 || mDisplay == null
                 || mDisplay.getDisplayId() != mTaskInfo.displayId
                 || oldLayoutResId != mLayoutResId) {
@@ -209,7 +205,7 @@
                 outResult.mRootView = null;
                 return;
             }
-            mDecorWindowContext = mContext.createConfigurationContext(taskConfig);
+            mDecorWindowContext = mContext.createConfigurationContext(mWindowDecorConfig);
             if (params.mLayoutResId != 0) {
                 outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext)
                         .inflate(params.mLayoutResId, null);
@@ -222,6 +218,7 @@
         }
 
         final Resources resources = mDecorWindowContext.getResources();
+        final Configuration taskConfig = mTaskInfo.getConfiguration();
         final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
         outResult.mWidth = taskBounds.width();
         outResult.mHeight = taskBounds.height();
@@ -470,6 +467,8 @@
         int mCaptionX;
         int mCaptionY;
 
+        Configuration mWindowDecorConfig;
+
         boolean mApplyStartTransactionOnDraw;
 
         void reset() {
@@ -484,6 +483,7 @@
             mCaptionY = 0;
 
             mApplyStartTransactionOnDraw = false;
+            mWindowDecorConfig = null;
         }
     }
 
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index dfbadae..eb650ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -69,10 +69,22 @@
 }
 
 filegroup {
+    name: "WMShellFlickerServicePlatinumTests-src",
+    srcs: [
+        "src/com/android/wm/shell/flicker/service/*/platinum/**/*.kt",
+        "src/com/android/wm/shell/flicker/service/*/scenarios/**/*.kt",
+        "src/com/android/wm/shell/flicker/service/common/**/*.kt",
+    ],
+}
+
+filegroup {
     name: "WMShellFlickerServiceTests-src",
     srcs: [
         "src/com/android/wm/shell/flicker/service/**/*.kt",
     ],
+    exclude_srcs: [
+        "src/com/android/wm/shell/flicker/service/*/platinum/**/*.kt",
+    ],
 }
 
 java_library {
@@ -114,6 +126,7 @@
         "flickertestapplib",
         "flickerlib",
         "flickerlib-helpers",
+        "flickerlib-trace_processor_shell",
         "platform-test-annotations",
         "wm-flicker-common-app-helpers",
         "wm-flicker-common-assertions",
@@ -143,6 +156,7 @@
         ":WMShellFlickerTestsSplitScreenGroup2-src",
         ":WMShellFlickerTestsSplitScreenBase-src",
         ":WMShellFlickerServiceTests-src",
+        ":WMShellFlickerServicePlatinumTests-src",
     ],
 }
 
@@ -210,3 +224,15 @@
         ":WMShellFlickerServiceTests-src",
     ],
 }
+
+android_test {
+    name: "WMShellFlickerServicePlatinumTests",
+    defaults: ["WMShellFlickerTestsDefault"],
+    additional_manifests: ["manifests/AndroidManifestService.xml"],
+    package_name: "com.android.wm.shell.flicker.service",
+    instrumentation_target_package: "com.android.wm.shell.flicker.service",
+    srcs: [
+        ":WMShellFlickerTestsBase-src",
+        ":WMShellFlickerServicePlatinumTests-src",
+    ],
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
index 87b20ed..5e6a6c9 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
@@ -73,7 +73,9 @@
         <option name="shell-timeout" value="6600s"/>
         <option name="test-timeout" value="6000s"/>
         <option name="hidden-api-checks" value="false"/>
+        <!-- TODO(b/288396763): re-enable when PerfettoListener is fixed
         <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
+        -->
         <!-- PerfettoListener related arguments -->
         <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
         <option name="instrumentation-arg"
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
index 6a87de4..ae130b8 100644
--- a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifest.xml
@@ -45,9 +45,13 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <!-- Enable bubble notification-->
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
+    <!-- Allow the test to connect to perfetto trace processor -->
+    <uses-permission android:name="android.permission.INTERNET"/>
 
-    <!-- Allow the test to write directly to /sdcard/ -->
-    <application android:requestLegacyExternalStorage="true" android:largeHeap="true">
+    <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
+    <application android:requestLegacyExternalStorage="true"
+                 android:networkSecurityConfig="@xml/network_security_config"
+                 android:largeHeap="true">
         <uses-library android:name="android.test.runner"/>
 
         <service android:name=".NotificationListener"
diff --git a/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml b/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml
new file mode 100644
index 0000000..4bd9ca0
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/res/xml/network_security_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">localhost</domain>
+    </domain-config>
+</network-security-config>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/common/Utils.kt
similarity index 97%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/common/Utils.kt
index fa723e3..5f15785 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/common/Utils.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.flicker.service
+package com.android.wm.shell.flicker.service.common
 
 import android.app.Instrumentation
 import android.platform.test.rule.NavigationModeRule
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
new file mode 100644
index 0000000..a5c5122
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CopyContentInSplitGesturalNavLandscape : CopyContentInSplit(Rotation.ROTATION_90) {
+    @ExpectedScenarios([]) @Test override fun copyContentInSplit() = super.copyContentInSplit()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
new file mode 100644
index 0000000..092fb67
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CopyContentInSplitGesturalNavPortrait : CopyContentInSplit(Rotation.ROTATION_0) {
+    @ExpectedScenarios([]) @Test override fun copyContentInSplit() = super.copyContentInSplit()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
new file mode 100644
index 0000000..8cb25fe
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByDividerGesturalNavLandscape :
+    DismissSplitScreenByDivider(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+    @Test
+    override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
new file mode 100644
index 0000000..fa1be63
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByDividerGesturalNavPortrait :
+    DismissSplitScreenByDivider(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+    @Test
+    override fun dismissSplitScreenByDivider() = super.dismissSplitScreenByDivider()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
new file mode 100644
index 0000000..aa35237
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByGoHomeGesturalNavLandscape :
+    DismissSplitScreenByGoHome(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+    @Test
+    override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
new file mode 100644
index 0000000..e195360
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DismissSplitScreenByGoHomeGesturalNavPortrait :
+    DismissSplitScreenByGoHome(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_EXIT"])
+    @Test
+    override fun dismissSplitScreenByGoHome() = super.dismissSplitScreenByGoHome()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
new file mode 100644
index 0000000..c1b3aad
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DragDividerToResizeGesturalNavLandscape : DragDividerToResize(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_RESIZE"])
+    @Test
+    override fun dragDividerToResize() = super.dragDividerToResize()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
new file mode 100644
index 0000000..c6e2e85
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class DragDividerToResizeGesturalNavPortrait : DragDividerToResize(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_RESIZE"])
+    @Test
+    override fun dragDividerToResize() = super.dragDividerToResize()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
new file mode 100644
index 0000000..5f771c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromAllAppsGesturalNavLandscape :
+    EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
new file mode 100644
index 0000000..729a401
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromAllAppsGesturalNavPortrait :
+    EnterSplitScreenByDragFromAllApps(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromAllApps() = super.enterSplitScreenByDragFromAllApps()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
new file mode 100644
index 0000000..6e4cf9f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromNotificationGesturalNavLandscape :
+    EnterSplitScreenByDragFromNotification(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromNotification() =
+        super.enterSplitScreenByDragFromNotification()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
new file mode 100644
index 0000000..cc28702
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromNotificationGesturalNavPortrait :
+    EnterSplitScreenByDragFromNotification(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromNotification() =
+        super.enterSplitScreenByDragFromNotification()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
new file mode 100644
index 0000000..736604f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromShortcutGesturalNavLandscape :
+    EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
new file mode 100644
index 0000000..8df8dfa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromShortcutGesturalNavPortrait :
+    EnterSplitScreenByDragFromShortcut(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromShortcut() = super.enterSplitScreenByDragFromShortcut()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
new file mode 100644
index 0000000..378f055
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromTaskbarGesturalNavLandscape :
+    EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
new file mode 100644
index 0000000..b33d262
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenByDragFromTaskbarGesturalNavPortrait :
+    EnterSplitScreenByDragFromTaskbar(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenByDragFromTaskbar() = super.enterSplitScreenByDragFromTaskbar()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
new file mode 100644
index 0000000..b1d3858
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenFromOverviewGesturalNavLandscape :
+    EnterSplitScreenFromOverview(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
new file mode 100644
index 0000000..6d824c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterSplitScreenFromOverviewGesturalNavPortrait :
+    EnterSplitScreenFromOverview(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["SPLIT_SCREEN_ENTER"])
+    @Test
+    override fun enterSplitScreenFromOverview() = super.enterSplitScreenFromOverview()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
new file mode 100644
index 0000000..f1d3d0c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchAppByDoubleTapDividerGesturalNavLandscape :
+    SwitchAppByDoubleTapDivider(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios([])
+    @Test
+    override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
new file mode 100644
index 0000000..a867bac
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchAppByDoubleTapDividerGesturalNavPortrait :
+    SwitchAppByDoubleTapDivider(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios([])
+    @Test
+    override fun switchAppByDoubleTapDivider() = super.switchAppByDoubleTapDivider()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
new file mode 100644
index 0000000..76247ba
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromAnotherAppGesturalNavLandscape :
+    SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
new file mode 100644
index 0000000..e179da8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromAnotherAppGesturalNavPortrait :
+    SwitchBackToSplitFromAnotherApp(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBackToSplitFromAnotherApp() = super.switchBackToSplitFromAnotherApp()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
new file mode 100644
index 0000000..20f554f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromHomeGesturalNavLandscape :
+    SwitchBackToSplitFromHome(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
new file mode 100644
index 0000000..f7776ee
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromHomeGesturalNavPortrait :
+    SwitchBackToSplitFromHome(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBackToSplitFromHome() = super.switchBackToSplitFromHome()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
new file mode 100644
index 0000000..00f6073
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromRecentGesturalNavLandscape :
+    SwitchBackToSplitFromRecent(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
new file mode 100644
index 0000000..b3340e7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBackToSplitFromRecentGesturalNavPortrait :
+    SwitchBackToSplitFromRecent(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBackToSplitFromRecent() = super.switchBackToSplitFromRecent()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
new file mode 100644
index 0000000..3da61e5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBetweenSplitPairsGesturalNavLandscape : SwitchBetweenSplitPairs(Rotation.ROTATION_90) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
new file mode 100644
index 0000000..627ae18
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class SwitchBetweenSplitPairsGesturalNavPortrait : SwitchBetweenSplitPairs(Rotation.ROTATION_0) {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun switchBetweenSplitPairs() = super.switchBetweenSplitPairs()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
new file mode 100644
index 0000000..f4e7298
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class UnlockKeyguardToSplitScreenGesturalNavLandscape : UnlockKeyguardToSplitScreen() {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
new file mode 100644
index 0000000..f38b2e8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service.splitscreen.flicker
+
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class UnlockKeyguardToSplitScreenGesturalNavPortrait : UnlockKeyguardToSplitScreen() {
+
+    @ExpectedScenarios(["QUICKSWITCH"])
+    @Test
+    override fun unlockKeyguardToSplitScreen() = super.unlockKeyguardToSplitScreen()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
index e530f63..245184c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
index e9fc437..1f2f1ec 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
index 416692c..ebbf7c5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
index 494a246..71e701c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
index 9b43816..c433b21 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
index 50151f1..3f087a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
index 76fbf60..767e7b5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
index f8e43f1..2592fd4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
index c2100f6..f2cbf24 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
index 70f3bed..538ed96 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -25,7 +25,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
index 86f394d..0dab5ad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
index d7b611e..ad3a2d4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
index 3cc5df0..b780a16 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
index 4a9c32f..329d61d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
index 383a6b3..a9933bbe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
@@ -23,7 +23,7 @@
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.wm.shell.flicker.service.Utils
+import com.android.wm.shell.flicker.service.common.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
 import org.junit.Before
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java
new file mode 100644
index 0000000..9655f97
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+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 org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.window.IWindowContainerToken;
+import android.window.TransitionInfo;
+import android.window.WindowContainerToken;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.TransitionInfoBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests of {@link BubblesTransitionObserver}.
+ */
+@SmallTest
+public class BubblesTransitionObserverTest {
+
+    @Mock
+    private BubbleController mBubbleController;
+    @Mock
+    private BubbleData mBubbleData;
+
+    @Mock
+    private IBinder mTransition;
+    @Mock
+    private SurfaceControl.Transaction mStartT;
+    @Mock
+    private SurfaceControl.Transaction mFinishT;
+
+    @Mock
+    private Bubble mBubble;
+
+    private BubblesTransitionObserver mTransitionObserver;
+
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTransitionObserver = new BubblesTransitionObserver(mBubbleController, mBubbleData);
+    }
+
+    @Test
+    public void testOnTransitionReady_open_collapsesStack() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        TransitionInfo info = createTransitionInfo(TRANSIT_OPEN, createTaskInfo(2));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_toFront_collapsesStack() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        TransitionInfo info = createTransitionInfo(TRANSIT_TO_FRONT, createTaskInfo(2));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_noTaskInfo_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        // Null task info
+        TransitionInfo info = createTransitionInfo(TRANSIT_TO_FRONT, null /* taskInfo */);
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_noTaskId_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        // Invalid task id
+        TransitionInfo info = createTransitionInfo(TRANSIT_TO_FRONT,
+                createTaskInfo(INVALID_TASK_ID));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_notOpening_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        // Transits that aren't opening
+        TransitionInfo info = createTransitionInfo(TRANSIT_CHANGE, createTaskInfo(2));
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        info = createTransitionInfo(TRANSIT_CLOSE, createTaskInfo(3));
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        info = createTransitionInfo(TRANSIT_TO_BACK, createTaskInfo(4));
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_stackAnimating_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(true); // Stack is animating
+
+        TransitionInfo info = createTransitionInfo(TRANSIT_OPEN, createTaskInfo(2));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_stackNotExpanded_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(false); // Stack is not expanded
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        TransitionInfo info = createTransitionInfo(TRANSIT_TO_FRONT, createTaskInfo(2));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_noSelectedBubble_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(null); // No selected bubble
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        TransitionInfo info = createTransitionInfo(TRANSIT_OPEN, createTaskInfo(2));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    @Test
+    public void testOnTransitionReady_openingMatchesExpanded_skip() {
+        when(mBubbleData.isExpanded()).thenReturn(true);
+        when(mBubbleData.getSelectedBubble()).thenReturn(mBubble);
+        when(mBubble.getTaskId()).thenReturn(1);
+        when(mBubbleController.isStackAnimating()).thenReturn(false);
+
+        // What's moving to front is same as the opened bubble
+        TransitionInfo info = createTransitionInfo(TRANSIT_TO_FRONT, createTaskInfo(1));
+
+        mTransitionObserver.onTransitionReady(mTransition, info, mStartT, mFinishT);
+
+        verify(mBubbleData, never()).setExpanded(eq(false));
+    }
+
+    private ActivityManager.RunningTaskInfo createTaskInfo(int taskId) {
+        final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+        taskInfo.taskId = taskId;
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        return taskInfo;
+    }
+
+    private TransitionInfo createTransitionInfo(int changeType,
+            ActivityManager.RunningTaskInfo info) {
+        final TransitionInfo.Change change = new TransitionInfo.Change(
+                new WindowContainerToken(mock(IWindowContainerToken.class)),
+                mock(SurfaceControl.class));
+        change.setMode(changeType);
+        change.setTaskInfo(info);
+
+        return new TransitionInfoBuilder(TRANSIT_OPEN, 0)
+                .addChange(change).build();
+    }
+
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
deleted file mode 100644
index 605a762..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ /dev/null
@@ -1,531 +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.wm.shell.desktopmode;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask;
-import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask;
-import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createHomeTask;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.testing.AndroidTestingRunner;
-import android.window.DisplayAreaInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransaction.Change;
-import android.window.WindowContainerTransaction.HierarchyOp;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
-import com.android.wm.shell.MockToken;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.sysui.ShellController;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class DesktopModeControllerTest extends ShellTestCase {
-
-    private static final int SECOND_DISPLAY = 2;
-
-    @Mock
-    private ShellController mShellController;
-    @Mock
-    private ShellTaskOrganizer mShellTaskOrganizer;
-    @Mock
-    private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
-    @Mock
-    private ShellExecutor mTestExecutor;
-    @Mock
-    private Handler mMockHandler;
-    @Mock
-    private Transitions mTransitions;
-    private DesktopModeController mController;
-    private DesktopModeTaskRepository mDesktopModeTaskRepository;
-    private ShellInit mShellInit;
-    private StaticMockitoSession mMockitoSession;
-
-    @Before
-    public void setUp() {
-        mMockitoSession = mockitoSession().mockStatic(DesktopModeStatus.class).startMocking();
-        when(DesktopModeStatus.isProto1Enabled()).thenReturn(true);
-        when(DesktopModeStatus.isActive(any())).thenReturn(true);
-
-        mShellInit = Mockito.spy(new ShellInit(mTestExecutor));
-
-        mDesktopModeTaskRepository = new DesktopModeTaskRepository();
-
-        mController = createController();
-
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>());
-
-        mShellInit.init();
-        clearInvocations(mShellTaskOrganizer);
-        clearInvocations(mRootTaskDisplayAreaOrganizer);
-        clearInvocations(mTransitions);
-    }
-
-    @After
-    public void tearDown() {
-        mMockitoSession.finishMocking();
-    }
-
-    @Test
-    public void instantiate_addInitCallback() {
-        verify(mShellInit).addInitCallback(any(), any());
-    }
-
-    @Test
-    public void instantiate_flagOff_doNotAddInitCallback() {
-        when(DesktopModeStatus.isProto1Enabled()).thenReturn(false);
-        clearInvocations(mShellInit);
-
-        createController();
-
-        verify(mShellInit, never()).addInitCallback(any(), any());
-    }
-
-    @Test
-    public void testDesktopModeEnabled_rootTdaSetToFreeform() {
-        DisplayAreaInfo displayAreaInfo = createMockDisplayArea();
-
-        mController.updateDesktopModeActive(true);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 1 change: Root TDA windowing mode
-        assertThat(wct.getChanges().size()).isEqualTo(1);
-        // Verify WCT has a change for setting windowing mode to freeform
-        Change change = wct.getChanges().get(displayAreaInfo.token.asBinder());
-        assertThat(change).isNotNull();
-        assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_FREEFORM);
-    }
-
-    @Test
-    public void testDesktopModeDisabled_rootTdaSetToFullscreen() {
-        DisplayAreaInfo displayAreaInfo = createMockDisplayArea();
-
-        mController.updateDesktopModeActive(false);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 1 change: Root TDA windowing mode
-        assertThat(wct.getChanges().size()).isEqualTo(1);
-        // Verify WCT has a change for setting windowing mode to fullscreen
-        Change change = wct.getChanges().get(displayAreaInfo.token.asBinder());
-        assertThat(change).isNotNull();
-        assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN);
-    }
-
-    @Test
-    public void testDesktopModeEnabled_windowingModeCleared() {
-        createMockDisplayArea();
-        RunningTaskInfo freeformTask = createFreeformTask();
-        RunningTaskInfo fullscreenTask = createFullscreenTask();
-        RunningTaskInfo homeTask = createHomeTask();
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
-                Arrays.asList(freeformTask, fullscreenTask, homeTask)));
-
-        mController.updateDesktopModeActive(true);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 2 changes: Root TDA windowing mode and 1 task
-        assertThat(wct.getChanges().size()).isEqualTo(2);
-        // No changes for tasks that are not standard or freeform
-        assertThat(wct.getChanges().get(fullscreenTask.token.asBinder())).isNull();
-        assertThat(wct.getChanges().get(homeTask.token.asBinder())).isNull();
-        // Standard freeform task has windowing mode cleared
-        Change change = wct.getChanges().get(freeformTask.token.asBinder());
-        assertThat(change).isNotNull();
-        assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
-    }
-
-    @Test
-    public void testDesktopModeDisabled_windowingModeAndBoundsCleared() {
-        createMockDisplayArea();
-        RunningTaskInfo freeformTask = createFreeformTask();
-        RunningTaskInfo fullscreenTask = createFullscreenTask();
-        RunningTaskInfo homeTask = createHomeTask();
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
-                Arrays.asList(freeformTask, fullscreenTask, homeTask)));
-
-        mController.updateDesktopModeActive(false);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 3 changes: Root TDA windowing mode and 2 tasks
-        assertThat(wct.getChanges().size()).isEqualTo(3);
-        // No changes to home task
-        assertThat(wct.getChanges().get(homeTask.token.asBinder())).isNull();
-        // Standard tasks have bounds cleared
-        assertThatBoundsCleared(wct.getChanges().get(freeformTask.token.asBinder()));
-        assertThatBoundsCleared(wct.getChanges().get(fullscreenTask.token.asBinder()));
-        // Freeform standard tasks have windowing mode cleared
-        assertThat(wct.getChanges().get(
-                freeformTask.token.asBinder()).getWindowingMode()).isEqualTo(
-                WINDOWING_MODE_UNDEFINED);
-    }
-
-    @Test
-    public void testDesktopModeEnabled_homeTaskBehindVisibleTask() {
-        createMockDisplayArea();
-        RunningTaskInfo fullscreenTask1 = createFullscreenTask();
-        fullscreenTask1.isVisible = true;
-        RunningTaskInfo fullscreenTask2 = createFullscreenTask();
-        fullscreenTask2.isVisible = false;
-        RunningTaskInfo homeTask = createHomeTask();
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
-                Arrays.asList(fullscreenTask1, fullscreenTask2, homeTask)));
-
-        mController.updateDesktopModeActive(true);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // Check that there are hierarchy changes for home task and visible task
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-        // First show home task
-        HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(homeTask.token.asBinder());
-
-        // Then visible task on top of it
-        HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(fullscreenTask1.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_allAppsInvisible_bringsToFront() {
-        // Set up two active tasks on desktop, task2 is on top of task1.
-        RunningTaskInfo freeformTask1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, freeformTask1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                DEFAULT_DISPLAY, freeformTask1.taskId, false /* visible */);
-        RunningTaskInfo freeformTask2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, freeformTask2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                DEFAULT_DISPLAY, freeformTask2.taskId, false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask1.taskId)).thenReturn(
-                freeformTask1);
-        when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask2.taskId)).thenReturn(
-                freeformTask2);
-
-        // Run show desktop apps logic
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        // Check wct has reorder calls
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-
-        // Task 1 appeared first, must be first reorder to top.
-        HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(freeformTask1.token.asBinder());
-
-        // Task 2 appeared last, must be last reorder to top.
-        HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(freeformTask2.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_appsAlreadyVisible_bringsToFront() {
-        final RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                true /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1);
-        final RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                true /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2);
-
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        // Check wct has reorder calls
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-        // Task 1 appeared first, must be first reorder to top.
-        HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(task1.token.asBinder());
-
-        // Task 2 appeared last, must be last reorder to top.
-        HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(task2.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_someAppsInvisible_reordersAll() {
-        final RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1);
-        final RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                true /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2);
-
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        // Both tasks should be reordered to top, even if one was already visible.
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-        final HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(task1.token.asBinder());
-        final HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(task2.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay() {
-        RunningTaskInfo taskDefaultDisplay = createFreeformTask(DEFAULT_DISPLAY);
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                DEFAULT_DISPLAY, taskDefaultDisplay.taskId, false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(taskDefaultDisplay.taskId)).thenReturn(
-                taskDefaultDisplay);
-
-        RunningTaskInfo taskSecondDisplay = createFreeformTask(SECOND_DISPLAY);
-        mDesktopModeTaskRepository.addActiveTask(SECOND_DISPLAY, taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                SECOND_DISPLAY, taskSecondDisplay.taskId, false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(taskSecondDisplay.taskId)).thenReturn(
-                taskSecondDisplay);
-
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        assertThat(wct.getHierarchyOps()).hasSize(1);
-        HierarchyOp op = wct.getHierarchyOps().get(0);
-        assertThat(op.getContainer()).isEqualTo(taskDefaultDisplay.token.asBinder());
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_noTasks_returnsZero() {
-        assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0);
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
-        RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                true /* visible */);
-
-        RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                true /* visible */);
-
-        assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2);
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
-        RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                true /* visible */);
-
-        RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                false /* visible */);
-
-        assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1);
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_twoTasksVisibleOnDifferentDisplays_returnsOne() {
-        RunningTaskInfo taskDefaultDisplay = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY,
-                taskDefaultDisplay.taskId,
-                true /* visible */);
-
-        RunningTaskInfo taskSecondDisplay = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(SECOND_DISPLAY, taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(SECOND_DISPLAY,
-                taskSecondDisplay.taskId,
-                true /* visible */);
-
-        assertThat(mController.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1);
-    }
-
-    @Test
-    public void testHandleTransitionRequest_desktopModeNotActive_returnsNull() {
-        when(DesktopModeStatus.isActive(any())).thenReturn(false);
-        WindowContainerTransaction wct = mController.handleRequest(
-                new Binder(),
-                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
-        assertThat(wct).isNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_unsupportedTransit_returnsNull() {
-        WindowContainerTransaction wct = mController.handleRequest(
-                new Binder(),
-                new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
-        assertThat(wct).isNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_notFreeform_returnsNull() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        WindowContainerTransaction wct = mController.handleRequest(
-                new Binder(),
-                new TransitionRequestInfo(TRANSIT_TO_FRONT, trigger, null /* remote */));
-        assertThat(wct).isNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_taskOpen_returnsWct() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.token = new MockToken().token();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        WindowContainerTransaction wct = mController.handleRequest(
-                mock(IBinder.class),
-                new TransitionRequestInfo(TRANSIT_OPEN, trigger, null /* remote */));
-        assertThat(wct).isNotNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_taskToFront_returnsWct() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.token = new MockToken().token();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        WindowContainerTransaction wct = mController.handleRequest(
-                mock(IBinder.class),
-                new TransitionRequestInfo(TRANSIT_TO_FRONT, trigger, null /* remote */));
-        assertThat(wct).isNotNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_taskOpen_doesNotStartAnotherTransition() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.token = new MockToken().token();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        mController.handleRequest(
-                mock(IBinder.class),
-                new TransitionRequestInfo(TRANSIT_OPEN, trigger, null /* remote */));
-        verifyZeroInteractions(mTransitions);
-    }
-
-    private DesktopModeController createController() {
-        return new DesktopModeController(mContext, mShellInit, mShellController,
-                mShellTaskOrganizer, mRootTaskDisplayAreaOrganizer, mTransitions,
-                mDesktopModeTaskRepository, mMockHandler, new TestShellExecutor());
-    }
-
-    private DisplayAreaInfo createMockDisplayArea() {
-        DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().token(),
-                mContext.getDisplayId(), 0);
-        when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId()))
-                .thenReturn(displayAreaInfo);
-        return displayAreaInfo;
-    }
-
-    private WindowContainerTransaction getDesktopModeSwitchTransaction() {
-        ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
-                WindowContainerTransaction.class);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            verify(mTransitions).startTransition(eq(TRANSIT_CHANGE), arg.capture(), any());
-        } else {
-            verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture());
-        }
-        return arg.getValue();
-    }
-
-    private WindowContainerTransaction getBringAppsToFrontTransaction() {
-        final ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
-                WindowContainerTransaction.class);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            verify(mTransitions).startTransition(eq(TRANSIT_NONE), arg.capture(), any());
-        } else {
-            verify(mShellTaskOrganizer).applyTransaction(arg.capture());
-        }
-        return arg.getValue();
-    }
-
-    private void assertThatBoundsCleared(Change change) {
-        assertThat((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) != 0).isTrue();
-        assertThat(change.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue();
-    }
-
-}
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 5d87cf8..be4a287 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
@@ -107,7 +107,7 @@
     @Before
     fun setUp() {
         mockitoSession = mockitoSession().mockStatic(DesktopModeStatus::class.java).startMocking()
-        whenever(DesktopModeStatus.isProto2Enabled()).thenReturn(true)
+        whenever(DesktopModeStatus.isEnabled()).thenReturn(true)
 
         shellInit = Mockito.spy(ShellInit(testExecutor))
         desktopModeTaskRepository = DesktopModeTaskRepository()
@@ -154,7 +154,7 @@
 
     @Test
     fun instantiate_flagOff_doNotAddInitCallback() {
-        whenever(DesktopModeStatus.isProto2Enabled()).thenReturn(false)
+        whenever(DesktopModeStatus.isEnabled()).thenReturn(false)
         clearInvocations(shellInit)
 
         createController()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 9e9e1ca..40ce785 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -257,7 +257,7 @@
     public void testGetRecentTasks_hasActiveDesktopTasks_proto2Enabled_groupFreeformTasks() {
         StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
                 DesktopModeStatus.class).startMocking();
-        when(DesktopModeStatus.isProto2Enabled()).thenReturn(true);
+        when(DesktopModeStatus.isEnabled()).thenReturn(true);
 
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -297,7 +297,7 @@
     public void testGetRecentTasks_hasActiveDesktopTasks_proto2Disabled_doNotGroupFreeformTasks() {
         StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
                 DesktopModeStatus.class).startMocking();
-        when(DesktopModeStatus.isProto2Enabled()).thenReturn(false);
+        when(DesktopModeStatus.isEnabled()).thenReturn(false);
 
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 7f0465a..d8afe68 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -55,7 +55,6 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -88,7 +87,6 @@
     @Mock private DisplayController mDisplayController;
     @Mock private DisplayLayout mDisplayLayout;
     @Mock private SyncTransactionQueue mSyncQueue;
-    @Mock private DesktopModeController mDesktopModeController;
     @Mock private DesktopTasksController mDesktopTasksController;
     @Mock private InputMonitor mInputMonitor;
     @Mock private InputManager mInputManager;
@@ -121,7 +119,6 @@
                         mShellController,
                         mSyncQueue,
                         mTransitions,
-                        Optional.of(mDesktopModeController),
                         Optional.of(mDesktopTasksController),
                         mDesktopModeWindowDecorFactory,
                         mMockInputMonitorFactory,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index de46b31..5c0e04a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -76,7 +76,7 @@
             minHeight = MIN_HEIGHT
             defaultMinSize = DEFAULT_MIN
             displayId = DISPLAY_ID
-            configuration.windowConfiguration.bounds = STARTING_BOUNDS
+            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
         }
         mockWindowDecoration.mDisplay = mockDisplay
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
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 6f0599a..c0c4498 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
@@ -88,7 +88,7 @@
             minHeight = MIN_HEIGHT
             defaultMinSize = DEFAULT_MIN
             displayId = DISPLAY_ID
-            configuration.windowConfiguration.bounds = STARTING_BOUNDS
+            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
         }
         mockWindowDecoration.mDisplay = mockDisplay
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
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 3465ddd..8913453 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
@@ -104,7 +104,7 @@
             minHeight = MIN_HEIGHT
             defaultMinSize = DEFAULT_MIN
             displayId = DISPLAY_ID
-            configuration.windowConfiguration.bounds = STARTING_BOUNDS
+            configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
         }
         mockDesktopWindowDecoration.mDisplay = mockDisplay
         whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
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 7fc1c99..76bc25a 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
@@ -39,6 +39,7 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Point;
@@ -116,6 +117,7 @@
     private SurfaceControl.Transaction mMockSurfaceControlFinishT;
     private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
     private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
+    private Configuration mWindowConfiguration = new Configuration();
     private int mCaptionMenuWidthId;
     private int mCaptionMenuShadowRadiusId;
     private int mCaptionMenuCornerRadiusId;
@@ -296,6 +298,7 @@
         taskInfo.isFocused = true;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
         taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
+        mWindowConfiguration.densityDpi = taskInfo.configuration.densityDpi;
 
         final SurfaceControl taskSurface = mock(SurfaceControl.class);
         final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
@@ -516,7 +519,7 @@
     private TestWindowDecoration createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
         return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
-                taskInfo, testSurface,
+                taskInfo, testSurface, mWindowConfiguration,
                 new MockObjectSupplier<>(mMockSurfaceControlBuilders,
                         () -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
                 new MockObjectSupplier<>(mMockSurfaceControlTransactions,
@@ -556,13 +559,15 @@
         TestWindowDecoration(Context context, DisplayController displayController,
                 ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo,
                 SurfaceControl taskSurface,
+                Configuration windowConfiguration,
                 Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
                 Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
                 Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
                 SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
             super(context, displayController, taskOrganizer, taskInfo, taskSurface,
-                    surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
-                    windowContainerTransactionSupplier, surfaceControlViewHostFactory);
+                    windowConfiguration, surfaceControlBuilderSupplier,
+                    surfaceControlTransactionSupplier, windowContainerTransactionSupplier,
+                    surfaceControlViewHostFactory);
         }
 
         @Override
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index fa9447a..47a7f35 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -85,7 +85,10 @@
     export_include_dirs: ["include"],
     export_shared_lib_headers: ["libz"],
     static_libs: ["libincfs-utils"],
-    whole_static_libs: ["libincfs-utils"],
+    whole_static_libs: [
+        "libandroidfw_pathutils",
+        "libincfs-utils",
+    ],
     export_static_lib_headers: ["libincfs-utils"],
     target: {
         android: {
@@ -137,6 +140,28 @@
     },
 }
 
+cc_library_static {
+    name: "libandroidfw_pathutils",
+    defaults: ["libandroidfw_defaults"],
+    host_supported: true,
+    export_include_dirs: ["include_pathutils"],
+    srcs: [
+        "PathUtils.cpp",
+    ],
+    shared_libs: [
+        "libutils",
+    ],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+    visibility: [
+        ":__subpackages__",
+        "//frameworks/base/tools/aapt",
+    ],
+}
+
 common_test_libs = [
     "libandroidfw",
     "libbase",
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 795bb3c..fd6e18e 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -26,6 +26,7 @@
 #include <androidfw/AssetDir.h>
 #include <androidfw/AssetManager.h>
 #include <androidfw/misc.h>
+#include <androidfw/PathUtils.h>
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/ZipFileRO.h>
 #include <cutils/atomic.h>
@@ -88,7 +89,7 @@
     const char* root = getenv("ANDROID_DATA");
     LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
     String8 path(root);
-    path.appendPath(kResourceCache);
+    appendPath(path, kResourceCache);
 
     char buf[256]; // 256 chars should be enough for anyone...
     strncpy(buf, pkgPath.c_str(), 255);
@@ -104,7 +105,7 @@
         }
         ++p;
     }
-    path.appendPath(filename);
+    appendPath(path, filename);
     path.append("@idmap");
 
     return path;
@@ -181,7 +182,7 @@
 
     String8 realPath(path);
     if (kAppZipName) {
-        realPath.appendPath(kAppZipName);
+        appendPath(realPath, kAppZipName);
     }
     ap.type = ::getFileType(realPath.c_str());
     if (ap.type == kFileTypeRegular) {
@@ -367,7 +368,7 @@
     LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
 
     String8 path(root);
-    path.appendPath(kSystemAssets);
+    appendPath(path, kSystemAssets);
 
     return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
 }
@@ -439,7 +440,7 @@
     LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
 
     String8 assetName(kAssetsRoot);
-    assetName.appendPath(fileName);
+    appendPath(assetName, fileName);
 
     /*
      * For each top-level asset path, search for the asset.
@@ -587,8 +588,8 @@
                 const char* data = getenv("ANDROID_DATA");
                 LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
                 String8 overlaysListPath(data);
-                overlaysListPath.appendPath(kResourceCache);
-                overlaysListPath.appendPath("overlays.list");
+                appendPath(overlaysListPath, kResourceCache);
+                appendPath(overlaysListPath, "overlays.list");
                 addSystemOverlays(overlaysListPath.c_str(), ap.path, sharedRes, nextEntryIdx);
 #endif
                 sharedRes = const_cast<AssetManager*>(this)->
@@ -789,7 +790,7 @@
     /* look at the filesystem on disk */
     if (ap.type == kFileTypeDirectory) {
         String8 path(ap.path);
-        path.appendPath(fileName);
+        appendPath(path, fileName);
 
         pAsset = openAssetFromFileLocked(path, mode);
 
@@ -841,9 +842,9 @@
     sourceName.append(zipFileName);
     sourceName.append(":");
     if (dirName.length() > 0) {
-        sourceName.appendPath(dirName);
+        appendPath(sourceName, dirName);
     }
-    sourceName.appendPath(fileName);
+    appendPath(sourceName, fileName);
     return sourceName;
 }
 
@@ -853,7 +854,7 @@
 String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
 {
     String8 path(ap.path);
-    if (rootDir != NULL) path.appendPath(rootDir);
+    if (rootDir != NULL) appendPath(path, rootDir);
     return path;
 }
 
@@ -897,7 +898,7 @@
 {
     Asset* pAsset = NULL;
 
-    if (strcasecmp(pathName.getPathExtension().c_str(), ".gz") == 0) {
+    if (strcasecmp(getPathExtension(pathName).c_str(), ".gz") == 0) {
         //printf("TRYING '%s'\n", (const char*) pathName);
         pAsset = Asset::createFromCompressedFile(pathName.c_str(), mode);
     } else {
@@ -1078,8 +1079,7 @@
     //printf("scanAndMergeDir: %s %s %s\n", ap.path.c_str(), rootDir, dirName);
 
     String8 path = createPathNameLocked(ap, rootDir);
-    if (dirName[0] != '\0')
-        path.appendPath(dirName);
+    if (dirName[0] != '\0') appendPath(path, dirName);
 
     SortedVector<AssetDir::FileInfo>* pContents = scanDirLocked(path);
     if (pContents == NULL)
@@ -1176,7 +1176,7 @@
             fileType = kFileTypeUnknown;
 #else
         // stat the file
-        fileType = ::getFileType(path.appendPathCopy(entry->d_name).c_str());
+        fileType = ::getFileType(appendPathCopy(path, entry->d_name).c_str());
 #endif
 
         if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
@@ -1184,9 +1184,9 @@
 
         AssetDir::FileInfo info;
         info.set(String8(entry->d_name), fileType);
-        if (strcasecmp(info.getFileName().getPathExtension().c_str(), ".gz") == 0)
-            info.setFileName(info.getFileName().getBasePath());
-        info.setSourceName(path.appendPathCopy(info.getFileName()));
+        if (strcasecmp(getPathExtension(info.getFileName()).c_str(), ".gz") == 0)
+            info.setFileName(getBasePath(info.getFileName()));
+        info.setSourceName(appendPathCopy(path, info.getFileName()));
         pContents->add(info);
     }
 
@@ -1220,7 +1220,7 @@
 
     /* convert "sounds" to "rootDir/sounds" */
     if (rootDir != NULL) dirName = rootDir;
-    dirName.appendPath(baseDirName);
+    appendPath(dirName, baseDirName);
 
     /*
      * Scan through the list of files, looking for a match.  The files in
@@ -1269,7 +1269,7 @@
             if (nextSlash == NULL) {
                 /* this is a file in the requested directory */
 
-                info.set(String8(nameBuf).getPathLeaf(), kFileTypeRegular);
+                info.set(getPathLeaf(String8(nameBuf)), kFileTypeRegular);
 
                 info.setSourceName(
                     createZipSourceNameLocked(zipName, dirName, info.getFileName()));
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 5ffec34..6523469 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1013,13 +1013,13 @@
     const auto& assets = GetApkAssets(step.cookie);
     log_stream << "\n\t" << prefix << ": " << (assets ? assets->GetDebugName() : "<null>")
                << " #" << step.cookie;
-    if (!step.config_name.isEmpty()) {
+    if (!step.config_name.empty()) {
       log_stream << " - " << step.config_name;
     }
   }
 
   log_stream << "\nBest matching is from "
-             << (last_resolution_.best_config_name.isEmpty() ? "default"
+             << (last_resolution_.best_config_name.empty() ? "default"
                                                    : last_resolution_.best_config_name)
              << " configuration of " << last_resolution_.best_package_name;
   return log_stream.str();
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index 3582609..1a6a952 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -30,6 +30,7 @@
 #include <utime.h>
 #include <zlib.h>
 
+#include <androidfw/PathUtils.h>
 #include <log/log.h>
 #include <utils/ByteOrder.h>
 #include <utils/KeyedVector.h>
@@ -606,14 +607,14 @@
             prefix += packageName;
         }
         if (domain.length() > 0) {
-            prefix.appendPath(domain);
+            appendPath(prefix, domain);
         }
 
         // pax extended means we don't put in a prefix field, and put a different
         // string in the basic name field.  We can also construct the full path name
         // out of the substrings we've now built.
         fullname = prefix;
-        fullname.appendPath(relpath);
+        appendPath(fullname, relpath);
 
         // ustar:
         //    [   0 : 100 ]; file name/path
@@ -654,7 +655,7 @@
         // Now build the pax *header* templated on the ustar header
         memcpy(paxHeader, buf, 512);
 
-        String8 leaf = fullname.getPathLeaf();
+        String8 leaf = getPathLeaf(fullname);
         memset(paxHeader, 0, 100);                  // rewrite the name area
         snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
         memset(paxHeader + 345, 0, 155);            // rewrite the prefix area
diff --git a/libs/androidfw/PathUtils.cpp b/libs/androidfw/PathUtils.cpp
new file mode 100644
index 0000000..df7a9f0
--- /dev/null
+++ b/libs/androidfw/PathUtils.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#include <androidfw/PathUtils.h>
+
+#include <utils/Compat.h>
+
+namespace android {
+
+String8 getPathLeaf(const String8& str) {
+    const char* cp;
+    const char*const buf = str.c_str();
+
+    cp = strrchr(buf, OS_PATH_SEPARATOR);
+    if (cp == nullptr)
+        return str;
+    else
+        return String8(cp+1);
+}
+
+String8 getPathDir(const String8& str8) {
+    const char* cp;
+    const char*const str = str8.c_str();
+
+    cp = strrchr(str, OS_PATH_SEPARATOR);
+    if (cp == nullptr)
+        return String8();
+    else
+        return String8(str, cp - str);
+}
+
+static char* findExtension(const String8& str8) {
+    const char* lastSlash;
+    const char* lastDot;
+    const char* const str = str8.c_str();
+
+    // only look at the filename
+    lastSlash = strrchr(str, OS_PATH_SEPARATOR);
+    if (lastSlash == nullptr)
+        lastSlash = str;
+    else
+        lastSlash++;
+
+    // find the last dot
+    lastDot = strrchr(lastSlash, '.');
+    if (lastDot == nullptr)
+        return nullptr;
+
+    // looks good, ship it
+    return const_cast<char*>(lastDot);
+}
+
+String8 getPathExtension(const String8& str) {
+    char* ext;
+
+    ext = findExtension(str);
+    if (ext != nullptr)
+        return String8(ext);
+    else
+        return String8();
+}
+
+String8 getBasePath(const String8& str8) {
+    char* ext;
+    const char* const str = str8.c_str();
+
+    ext = findExtension(str8);
+    if (ext == nullptr)
+        return str8;
+    else
+        return String8(str, ext - str);
+}
+
+static void setPathName(String8& s, const char* name) {
+    size_t len = strlen(name);
+    char* buf = s.lockBuffer(len);
+
+    memcpy(buf, name, len);
+
+    // remove trailing path separator, if present
+    if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
+    buf[len] = '\0';
+
+    s.unlockBuffer(len);
+}
+
+String8& appendPath(String8& str, const char* name) {
+    // TODO: The test below will fail for Win32 paths. Fix later or ignore.
+    if (name[0] != OS_PATH_SEPARATOR) {
+        if (*name == '\0') {
+            // nothing to do
+            return str;
+        }
+
+        size_t len = str.length();
+        if (len == 0) {
+            // no existing filename, just use the new one
+            setPathName(str, name);
+            return str;
+        }
+
+        // make room for oldPath + '/' + newPath
+        int newlen = strlen(name);
+
+        char* buf = str.lockBuffer(len+1+newlen);
+
+        // insert a '/' if needed
+        if (buf[len-1] != OS_PATH_SEPARATOR)
+            buf[len++] = OS_PATH_SEPARATOR;
+
+        memcpy(buf+len, name, newlen+1);
+        len += newlen;
+
+        str.unlockBuffer(len);
+        return str;
+    } else {
+        setPathName(str, name);
+        return str;
+    }
+}
+
+} // namespace android
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index ec14316..099287c 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6291,13 +6291,13 @@
         if (append) {
             outString->append(tmp);
         } else {
-            outString->setTo(tmp);
+            *outString = tmp;
         }
     } else {
         if (append) {
             outString->append(String16(s, len));
         } else {
-            outString->setTo(s, len);
+            *outString = String16(s, len);
         }
     }
 
@@ -7500,10 +7500,10 @@
         *pOverlayCrc = dtohl(map[3]);
     }
     if (pTargetPath) {
-        pTargetPath->setTo(reinterpret_cast<const char*>(map + 4));
+        *pTargetPath = reinterpret_cast<const char*>(map + 4);
     }
     if (pOverlayPath) {
-        pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t)));
+        *pOverlayPath = reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t));
     }
     return true;
 }
diff --git a/libs/androidfw/include_pathutils/androidfw/PathUtils.h b/libs/androidfw/include_pathutils/androidfw/PathUtils.h
new file mode 100644
index 0000000..4debe8d
--- /dev/null
+++ b/libs/androidfw/include_pathutils/androidfw/PathUtils.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+
+/* This library contains path manipulation functions that are used only by androidfw and aapt.
+ * When it's possible, migrate all uses to std::filesystem::path.
+ */
+
+namespace android {
+
+/**
+ * Get just the filename component.
+ *
+ * DEPRECATED: use std::filesystem::path::filename
+ *
+ * "/tmp/foo/bar.c" --> "bar.c"
+ */
+String8 getPathLeaf(const String8& str);
+
+/**
+ * Remove the last (file name) component, leaving just the directory
+ * name.
+ *
+ * DEPRECATED: use std::filesystem::path::parent_path
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo"
+ * "/tmp" --> "" // ????? shouldn't this be "/" ???? XXX
+ * "bar.c" --> ""
+ */
+String8 getPathDir(const String8& str);
+
+/**
+ * Return the filename extension.  This is the last '.' and any number
+ * of characters that follow it.  The '.' is included in case we
+ * decide to expand our definition of what constitutes an extension.
+ *
+ * DEPRECATED: use std::filesystem::path::extension
+ *
+ * "/tmp/foo/bar.c" --> ".c"
+ * "/tmp" --> ""
+ * "/tmp/foo.bar/baz" --> ""
+ * "foo.jpeg" --> ".jpeg"
+ * "foo." --> ""
+ */
+String8 getPathExtension(const String8& str);
+
+/**
+ * Return the path without the extension.  Rules for what constitutes
+ * an extension are described in the comment for getPathExtension().
+ *
+ * DEPRECATED: use std::filesystem::path::stem and std::filesystem::path::parent_path
+ *
+ * "/tmp/foo/bar.c" --> "/tmp/foo/bar"
+ */
+String8 getBasePath(const String8& str);
+
+/**
+ * Add a component to the pathname.  We guarantee that there is
+ * exactly one path separator between the old path and the new.
+ * If there is no existing name, we just copy the new name in.
+ *
+ * DEPRECATED: use std::filesystem::path::operator/=
+ *
+ * If leaf is a fully qualified path (i.e. starts with '/', it
+ * replaces whatever was there before.
+ */
+String8& appendPath(String8& str, const char* leaf);
+inline String8& appendPath(String8& str, const String8& leaf) {
+    return appendPath(str, leaf.c_str());
+}
+
+/**
+ * Like appendPath(), but does not affect this string.  Returns a new one instead.
+ *
+ * DEPRECATED: use std::filesystem::operator/
+ */
+inline String8 appendPathCopy(String8 str, const char* leaf) { return appendPath(str, leaf); }
+inline String8 appendPathCopy(String8 str, const String8& leaf) {
+    return appendPath(str, leaf.c_str());
+}
+
+} // namespace android
diff --git a/libs/androidfw/tests/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp
index ec478b0..07bd175 100644
--- a/libs/androidfw/tests/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -159,17 +159,17 @@
   EXPECT_TRUE(TestParse("feminine", &config));
   EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_FEMININE, config.grammaticalInflection);
   EXPECT_EQ(SDK_U, config.sdkVersion);
-  EXPECT_EQ(std::string("feminine-v34"), config.toString().string());
+  EXPECT_EQ(std::string("feminine-v34"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("masculine", &config));
   EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_MASCULINE, config.grammaticalInflection);
   EXPECT_EQ(SDK_U, config.sdkVersion);
-  EXPECT_EQ(std::string("masculine-v34"), config.toString().string());
+  EXPECT_EQ(std::string("masculine-v34"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("neuter", &config));
   EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_NEUTER, config.grammaticalInflection);
   EXPECT_EQ(SDK_U, config.sdkVersion);
-  EXPECT_EQ(std::string("neuter-v34"), config.toString().string());
+  EXPECT_EQ(std::string("neuter-v34"), config.toString().c_str());
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 945981b..faac514 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -468,7 +468,7 @@
   String16 name(u"com.android.sparse:integer/foo_9");
   uint32_t flags;
   uint32_t resid =
-      table.identifierForName(name.string(), name.size(), nullptr, 0, nullptr, 0, &flags);
+      table.identifierForName(name.c_str(), name.size(), nullptr, 0, nullptr, 0, &flags);
   ASSERT_NE(0u, resid);
 
   Res_value val;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 529a49e9..c959db3 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -120,9 +120,9 @@
         if (name) {
             const char* lastPeriod = strrchr(name, '.');
             if (lastPeriod) {
-                mName.setTo(lastPeriod + 1);
+                mName = (lastPeriod + 1);
             } else {
-                mName.setTo(name);
+                mName = name;
             }
         }
     }
diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp
index a17f2f7..7aef7a5 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -203,10 +203,9 @@
         if (advances) {
             advancesArray.reset(new jfloat[count]);
         }
-        minikin::MinikinRect bounds;
         const float advance = MinikinUtils::measureText(
                 paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, start, count,
-                contextCount, advancesArray.get(), &bounds);
+                contextCount, advancesArray.get(), nullptr);
         if (advances) {
             env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
         }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 120d812..d54c5f5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -162,7 +162,6 @@
     destroyHardwareResources();
     mAnimationContext->destroy();
     mRenderThread.cacheManager().onContextStopped(this);
-    mHintSessionWrapper.destroy();
 }
 
 static void setBufferCount(ANativeWindow* window) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index e2b541a..ee3b2e4 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -25,6 +25,7 @@
 #include <android/sync.h>
 #include <gui/TraceUtils.h>
 #include <include/gpu/ganesh/SkSurfaceGanesh.h>
+#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
 #include <ui/FatVector.h>
 #include <vk/GrVkExtensions.h>
 #include <vk/GrVkTypes.h>
@@ -599,7 +600,7 @@
                             surface, SkSurfaces::BackendHandleAccess::kFlushRead);
                 if (backendRenderTarget.isValid()) {
                     GrVkImageInfo info;
-                    if (backendRenderTarget.getVkImageInfo(&info)) {
+                    if (GrBackendRenderTargets::GetVkImageInfo(backendRenderTarget, &info)) {
                         image = info.fImage;
                     } else {
                         ALOGE("Frame boundary: backend is not vulkan");
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index d344a981..858813f 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -152,8 +152,8 @@
     }
     mPrivacyPolicy = privacyPolicy;
 
-    mReceiverPkg = String8(in->readString16()).string();
-    mReceiverCls = String8(in->readString16()).string();
+    mReceiverPkg = String8(in->readString16()).c_str();
+    mReceiverCls = String8(in->readString16()).c_str();
 
     int32_t gzip;
     err = in->readInt32(&gzip);
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 9695e6f..abd9284 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -63,10 +63,10 @@
 
 std::shared_ptr<PointerController> PointerController::create(
         const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
-        SpriteController& spriteController) {
+        SpriteController& spriteController, bool enabled) {
     // using 'new' to access non-public constructor
     std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
-            new PointerController(policy, looper, spriteController));
+            new PointerController(policy, looper, spriteController, enabled));
 
     /*
      * Now we need to hook up the constructed PointerController object to its callbacks.
@@ -85,9 +85,10 @@
 }
 
 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
-                                     const sp<Looper>& looper, SpriteController& spriteController)
+                                     const sp<Looper>& looper, SpriteController& spriteController,
+                                     bool enabled)
       : PointerController(
-                policy, looper, spriteController,
+                policy, looper, spriteController, enabled,
                 [](const sp<android::gui::WindowInfosListener>& listener) {
                     SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
                 },
@@ -97,9 +98,10 @@
 
 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
                                      const sp<Looper>& looper, SpriteController& spriteController,
-                                     WindowListenerConsumer registerListener,
+                                     bool enabled, WindowListenerConsumer registerListener,
                                      WindowListenerConsumer unregisterListener)
-      : mContext(policy, looper, spriteController, *this),
+      : mEnabled(enabled),
+        mContext(policy, looper, spriteController, *this),
         mCursorController(mContext),
         mDisplayInfoListener(sp<DisplayInfoListener>::make(this)),
         mUnregisterWindowInfosListener(std::move(unregisterListener)) {
@@ -119,10 +121,14 @@
 }
 
 std::optional<FloatRect> PointerController::getBounds() const {
+    if (!mEnabled) return {};
+
     return mCursorController.getBounds();
 }
 
 void PointerController::move(float deltaX, float deltaY) {
+    if (!mEnabled) return;
+
     const int32_t displayId = mCursorController.getDisplayId();
     vec2 transformed;
     {
@@ -134,6 +140,8 @@
 }
 
 void PointerController::setPosition(float x, float y) {
+    if (!mEnabled) return;
+
     const int32_t displayId = mCursorController.getDisplayId();
     vec2 transformed;
     {
@@ -145,6 +153,11 @@
 }
 
 FloatPoint PointerController::getPosition() const {
+    if (!mEnabled) {
+        return FloatPoint{AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION};
+    }
+
     const int32_t displayId = mCursorController.getDisplayId();
     const auto p = mCursorController.getPosition();
     {
@@ -155,20 +168,28 @@
 }
 
 int32_t PointerController::getDisplayId() const {
+    if (!mEnabled) return ADISPLAY_ID_NONE;
+
     return mCursorController.getDisplayId();
 }
 
 void PointerController::fade(Transition transition) {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
     mCursorController.fade(transition);
 }
 
 void PointerController::unfade(Transition transition) {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
     mCursorController.unfade(transition);
 }
 
 void PointerController::setPresentation(Presentation presentation) {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
 
     if (mLocked.presentation == presentation) {
@@ -193,6 +214,8 @@
 
 void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
                                  BitSet32 spotIdBits, int32_t displayId) {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
     std::array<PointerCoords, MAX_POINTERS> outSpotCoords{};
     const ui::Transform& transform = getTransformForDisplayLocked(displayId);
@@ -216,6 +239,8 @@
 }
 
 void PointerController::clearSpots() {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
     clearSpotsLocked();
 }
@@ -277,11 +302,15 @@
 }
 
 void PointerController::updatePointerIcon(PointerIconStyle iconId) {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
     mCursorController.updatePointerIcon(iconId);
 }
 
 void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
+    if (!mEnabled) return;
+
     std::scoped_lock lock(getLock());
     mCursorController.setCustomPointerIcon(icon);
 }
@@ -325,8 +354,12 @@
     return it != di.end() ? it->transform : kIdentityTransform;
 }
 
-void PointerController::dump(std::string& dump) {
-    dump += INDENT "PointerController:\n";
+std::string PointerController::dump() {
+    if (!mEnabled) {
+        return INDENT "PointerController: DISABLED due to ongoing PointerChoreographer refactor\n";
+    }
+
+    std::string dump = INDENT "PointerController:\n";
     std::scoped_lock lock(getLock());
     dump += StringPrintf(INDENT2 "Presentation: %s\n",
                          ftl::enum_string(mLocked.presentation).c_str());
@@ -339,6 +372,7 @@
     for (const auto& [_, spotController] : mLocked.spotControllers) {
         spotController.dump(dump, INDENT3);
     }
+    return dump;
 }
 
 } // namespace android
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 01748a8..aa7ca3c 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -47,7 +47,7 @@
 public:
     static std::shared_ptr<PointerController> create(
             const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
-            SpriteController& spriteController);
+            SpriteController& spriteController, bool enabled);
 
     ~PointerController() override;
 
@@ -75,7 +75,7 @@
     void onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo>& displayInfos)
             REQUIRES(getLock());
 
-    void dump(std::string& dump);
+    std::string dump();
 
 protected:
     using WindowListenerConsumer =
@@ -83,12 +83,13 @@
 
     // Constructor used to test WindowInfosListener registration.
     PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
-                      SpriteController& spriteController, WindowListenerConsumer registerListener,
+                      SpriteController& spriteController, bool enabled,
+                      WindowListenerConsumer registerListener,
                       WindowListenerConsumer unregisterListener);
 
 private:
     PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
-                      SpriteController& spriteController);
+                      SpriteController& spriteController, bool enabled);
 
     friend PointerControllerContext::LooperCallback;
     friend PointerControllerContext::MessageHandler;
@@ -99,6 +100,8 @@
     // we use the DisplayInfoListener's lock in PointerController.
     std::mutex& getLock() const;
 
+    const bool mEnabled;
+
     PointerControllerContext mContext;
 
     MouseCursorController mCursorController;
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index 3e2e43f..94faf4a 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -181,7 +181,8 @@
     EXPECT_CALL(*mSpriteController, createSprite())
             .WillOnce(Return(mPointerSprite));
 
-    mPointerController = PointerController::create(mPolicy, mLooper, *mSpriteController);
+    mPointerController =
+            PointerController::create(mPolicy, mLooper, *mSpriteController, /*enabled=*/true);
 }
 
 PointerControllerTest::~PointerControllerTest() {
@@ -321,6 +322,7 @@
                           const sp<Looper>& looper, SpriteController& spriteController)
           : PointerController(
                     new MockPointerControllerPolicyInterface(), looper, spriteController,
+                    /*enabled=*/true,
                     [&registeredListener](const sp<android::gui::WindowInfosListener>& listener) {
                         // Register listener
                         registeredListener = listener;
diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp
index 3716e01..60bb00a 100644
--- a/libs/services/src/os/DropBoxManager.cpp
+++ b/libs/services/src/os/DropBoxManager.cpp
@@ -196,7 +196,7 @@
     vector<uint8_t> dataArg;
     dataArg.assign(data, data + size);
     Status status = service->addData(tag, dataArg, flags);
-    ALOGD("service->add returned %s", status.toString8().string());
+    ALOGD("service->add returned %s", status.toString8().c_str());
     return status;
 }
 
@@ -230,7 +230,7 @@
     android::base::unique_fd uniqueFd(fd);
     android::os::ParcelFileDescriptor parcelFd(std::move(uniqueFd));
     Status status = service->addFile(tag, parcelFd, flags);
-    ALOGD("service->add returned %s", status.toString8().string());
+    ALOGD("service->add returned %s", status.toString8().c_str());
     return status;
 }
 
diff --git a/location/Android.bp b/location/Android.bp
index 46dca74..cfe0e49 100644
--- a/location/Android.bp
+++ b/location/Android.bp
@@ -7,18 +7,18 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-//location sources that will populate the new module
 filegroup {
-    name: "framework-location-nonupdatable-sources",
+    name: "framework-location-sources",
     srcs: [
-        "placeholder_java/android/location/Placeholder.java",
+        "java/**/*.java",
+        "java/**/*.aidl",
     ],
 }
 
 java_sdk_library {
     name: "framework-location",
     srcs: [
-        ":framework-location-nonupdatable-sources",
+        ":framework-location-sources",
     ],
     defaults: ["framework-non-updatable-unbundled-defaults"],
     permitted_packages: [
diff --git a/location/api/current.txt b/location/api/current.txt
index d802177..33effdd 100644
--- a/location/api/current.txt
+++ b/location/api/current.txt
@@ -1 +1,725 @@
 // Signature format: 2.0
+package android.location {
+
+  public class Address implements android.os.Parcelable {
+    ctor public Address(java.util.Locale);
+    method public void clearLatitude();
+    method public void clearLongitude();
+    method public int describeContents();
+    method public String getAddressLine(int);
+    method public String getAdminArea();
+    method public String getCountryCode();
+    method public String getCountryName();
+    method public android.os.Bundle getExtras();
+    method public String getFeatureName();
+    method public double getLatitude();
+    method public java.util.Locale getLocale();
+    method public String getLocality();
+    method public double getLongitude();
+    method public int getMaxAddressLineIndex();
+    method public String getPhone();
+    method public String getPostalCode();
+    method public String getPremises();
+    method public String getSubAdminArea();
+    method public String getSubLocality();
+    method public String getSubThoroughfare();
+    method public String getThoroughfare();
+    method public String getUrl();
+    method public boolean hasLatitude();
+    method public boolean hasLongitude();
+    method public void setAddressLine(int, String);
+    method public void setAdminArea(String);
+    method public void setCountryCode(String);
+    method public void setCountryName(String);
+    method public void setExtras(android.os.Bundle);
+    method public void setFeatureName(String);
+    method public void setLatitude(double);
+    method public void setLocality(String);
+    method public void setLongitude(double);
+    method public void setPhone(String);
+    method public void setPostalCode(String);
+    method public void setPremises(String);
+    method public void setSubAdminArea(String);
+    method public void setSubLocality(String);
+    method public void setSubThoroughfare(String);
+    method public void setThoroughfare(String);
+    method public void setUrl(String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.Address> CREATOR;
+  }
+
+  @Deprecated public class Criteria implements android.os.Parcelable {
+    ctor @Deprecated public Criteria();
+    ctor @Deprecated public Criteria(android.location.Criteria);
+    method @Deprecated public int describeContents();
+    method @Deprecated public int getAccuracy();
+    method @Deprecated public int getBearingAccuracy();
+    method @Deprecated public int getHorizontalAccuracy();
+    method @Deprecated public int getPowerRequirement();
+    method @Deprecated public int getSpeedAccuracy();
+    method @Deprecated public int getVerticalAccuracy();
+    method @Deprecated public boolean isAltitudeRequired();
+    method @Deprecated public boolean isBearingRequired();
+    method @Deprecated public boolean isCostAllowed();
+    method @Deprecated public boolean isSpeedRequired();
+    method @Deprecated public void setAccuracy(int);
+    method @Deprecated public void setAltitudeRequired(boolean);
+    method @Deprecated public void setBearingAccuracy(int);
+    method @Deprecated public void setBearingRequired(boolean);
+    method @Deprecated public void setCostAllowed(boolean);
+    method @Deprecated public void setHorizontalAccuracy(int);
+    method @Deprecated public void setPowerRequirement(int);
+    method @Deprecated public void setSpeedAccuracy(int);
+    method @Deprecated public void setSpeedRequired(boolean);
+    method @Deprecated public void setVerticalAccuracy(int);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final int ACCURACY_COARSE = 2; // 0x2
+    field @Deprecated public static final int ACCURACY_FINE = 1; // 0x1
+    field @Deprecated public static final int ACCURACY_HIGH = 3; // 0x3
+    field @Deprecated public static final int ACCURACY_LOW = 1; // 0x1
+    field @Deprecated public static final int ACCURACY_MEDIUM = 2; // 0x2
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR;
+    field @Deprecated public static final int NO_REQUIREMENT = 0; // 0x0
+    field @Deprecated public static final int POWER_HIGH = 3; // 0x3
+    field @Deprecated public static final int POWER_LOW = 1; // 0x1
+    field @Deprecated public static final int POWER_MEDIUM = 2; // 0x2
+  }
+
+  public final class Geocoder {
+    ctor public Geocoder(@NonNull android.content.Context);
+    ctor public Geocoder(@NonNull android.content.Context, @NonNull java.util.Locale);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int) throws java.io.IOException;
+    method public void getFromLocation(@FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange int, @NonNull android.location.Geocoder.GeocodeListener);
+    method @Deprecated @Nullable public java.util.List<android.location.Address> getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double) throws java.io.IOException;
+    method public void getFromLocationName(@NonNull String, @IntRange int, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @FloatRange(from=-90.0, to=90.0) double, @FloatRange(from=-180.0, to=180.0) double, @NonNull android.location.Geocoder.GeocodeListener);
+    method public static boolean isPresent();
+  }
+
+  public static interface Geocoder.GeocodeListener {
+    method public default void onError(@Nullable String);
+    method public void onGeocode(@NonNull java.util.List<android.location.Address>);
+  }
+
+  public final class GnssAntennaInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public double getCarrierFrequencyMHz();
+    method @NonNull public android.location.GnssAntennaInfo.PhaseCenterOffset getPhaseCenterOffset();
+    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getPhaseCenterVariationCorrections();
+    method @Nullable public android.location.GnssAntennaInfo.SphericalCorrections getSignalGainCorrections();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo> CREATOR;
+  }
+
+  public static class GnssAntennaInfo.Builder {
+    ctor @Deprecated public GnssAntennaInfo.Builder();
+    ctor public GnssAntennaInfo.Builder(double, @NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
+    ctor public GnssAntennaInfo.Builder(@NonNull android.location.GnssAntennaInfo);
+    method @NonNull public android.location.GnssAntennaInfo build();
+    method @NonNull public android.location.GnssAntennaInfo.Builder setCarrierFrequencyMHz(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterOffset(@NonNull android.location.GnssAntennaInfo.PhaseCenterOffset);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setPhaseCenterVariationCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
+    method @NonNull public android.location.GnssAntennaInfo.Builder setSignalGainCorrections(@Nullable android.location.GnssAntennaInfo.SphericalCorrections);
+  }
+
+  public static interface GnssAntennaInfo.Listener {
+    method public void onGnssAntennaInfoReceived(@NonNull java.util.List<android.location.GnssAntennaInfo>);
+  }
+
+  public static final class GnssAntennaInfo.PhaseCenterOffset implements android.os.Parcelable {
+    ctor public GnssAntennaInfo.PhaseCenterOffset(double, double, double, double, double, double);
+    method public int describeContents();
+    method @FloatRange public double getXOffsetMm();
+    method @FloatRange public double getXOffsetUncertaintyMm();
+    method @FloatRange public double getYOffsetMm();
+    method @FloatRange public double getYOffsetUncertaintyMm();
+    method @FloatRange public double getZOffsetMm();
+    method @FloatRange public double getZOffsetUncertaintyMm();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.PhaseCenterOffset> CREATOR;
+  }
+
+  public static final class GnssAntennaInfo.SphericalCorrections implements android.os.Parcelable {
+    ctor public GnssAntennaInfo.SphericalCorrections(@NonNull double[][], @NonNull double[][]);
+    method public int describeContents();
+    method @NonNull public double[][] getCorrectionUncertaintiesArray();
+    method @NonNull public double[][] getCorrectionsArray();
+    method @FloatRange(from=0.0f, to=180.0f) public double getDeltaPhi();
+    method @FloatRange(from=0.0f, to=360.0f) public double getDeltaTheta();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR;
+  }
+
+  public final class GnssAutomaticGainControl implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public long getCarrierFrequencyHz();
+    method public int getConstellationType();
+    method @FloatRange(from=0xffffd8f0, to=10000) public double getLevelDb();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAutomaticGainControl> CREATOR;
+  }
+
+  public static final class GnssAutomaticGainControl.Builder {
+    ctor public GnssAutomaticGainControl.Builder();
+    ctor public GnssAutomaticGainControl.Builder(@NonNull android.location.GnssAutomaticGainControl);
+    method @NonNull public android.location.GnssAutomaticGainControl build();
+    method @NonNull public android.location.GnssAutomaticGainControl.Builder setCarrierFrequencyHz(@IntRange(from=0) long);
+    method @NonNull public android.location.GnssAutomaticGainControl.Builder setConstellationType(int);
+    method @NonNull public android.location.GnssAutomaticGainControl.Builder setLevelDb(@FloatRange(from=0xffffd8f0, to=10000) double);
+  }
+
+  public final class GnssCapabilities implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.location.GnssSignalType> getGnssSignalTypes();
+    method public int hasAccumulatedDeltaRange();
+    method public boolean hasAntennaInfo();
+    method public boolean hasGeofencing();
+    method @Deprecated public boolean hasGnssAntennaInfo();
+    method public boolean hasLowPowerMode();
+    method public boolean hasMeasurementCorrections();
+    method public boolean hasMeasurementCorrectionsExcessPathLength();
+    method public boolean hasMeasurementCorrectionsForDriving();
+    method public boolean hasMeasurementCorrectionsLosSats();
+    method public boolean hasMeasurementCorrectionsReflectingPlane();
+    method public boolean hasMeasurementCorrelationVectors();
+    method public boolean hasMeasurements();
+    method public boolean hasMsa();
+    method public boolean hasMsb();
+    method public boolean hasNavigationMessages();
+    method public boolean hasOnDemandTime();
+    method public boolean hasPowerMultibandAcquisition();
+    method public boolean hasPowerMultibandTracking();
+    method public boolean hasPowerOtherModes();
+    method public boolean hasPowerSinglebandAcquisition();
+    method public boolean hasPowerSinglebandTracking();
+    method public boolean hasPowerTotal();
+    method public boolean hasSatelliteBlocklist();
+    method public boolean hasSatellitePvt();
+    method public boolean hasScheduling();
+    method public boolean hasSingleShotFix();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CAPABILITY_SUPPORTED = 1; // 0x1
+    field public static final int CAPABILITY_UNKNOWN = 0; // 0x0
+    field public static final int CAPABILITY_UNSUPPORTED = 2; // 0x2
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR;
+  }
+
+  public static final class GnssCapabilities.Builder {
+    ctor public GnssCapabilities.Builder();
+    ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities);
+    method @NonNull public android.location.GnssCapabilities build();
+    method @NonNull public android.location.GnssCapabilities.Builder setGnssSignalTypes(@NonNull java.util.List<android.location.GnssSignalType>);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasAccumulatedDeltaRange(int);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsForDriving(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrelationVectors(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMsa(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasMsb(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasOnDemandTime(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandAcquisition(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerMultibandTracking(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerOtherModes(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandAcquisition(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerSinglebandTracking(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasPowerTotal(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasSatellitePvt(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasScheduling(boolean);
+    method @NonNull public android.location.GnssCapabilities.Builder setHasSingleShotFix(boolean);
+  }
+
+  public final class GnssClock implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getBiasNanos();
+    method @FloatRange(from=0.0f) public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method @FloatRange(from=0.0f) public double getDriftUncertaintyNanosPerSecond();
+    method public long getElapsedRealtimeNanos();
+    method @FloatRange(from=0.0f) public double getElapsedRealtimeUncertaintyNanos();
+    method public long getFullBiasNanos();
+    method public int getHardwareClockDiscontinuityCount();
+    method public int getLeapSecond();
+    method @FloatRange(from=0.0) public double getReferenceCarrierFrequencyHzForIsb();
+    method @NonNull public String getReferenceCodeTypeForIsb();
+    method public int getReferenceConstellationTypeForIsb();
+    method public long getTimeNanos();
+    method @FloatRange(from=0.0f) public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasElapsedRealtimeNanos();
+    method public boolean hasElapsedRealtimeUncertaintyNanos();
+    method public boolean hasFullBiasNanos();
+    method public boolean hasLeapSecond();
+    method public boolean hasReferenceCarrierFrequencyHzForIsb();
+    method public boolean hasReferenceCodeTypeForIsb();
+    method public boolean hasReferenceConstellationTypeForIsb();
+    method public boolean hasTimeUncertaintyNanos();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
+  }
+
+  public final class GnssMeasurement implements android.os.Parcelable {
+    method public int describeContents();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
+    method @Deprecated public double getAutomaticGainControlLevelDb();
+    method @FloatRange(from=0, to=63) public double getBasebandCn0DbHz();
+    method @Deprecated public long getCarrierCycles();
+    method public float getCarrierFrequencyHz();
+    method @Deprecated public double getCarrierPhase();
+    method @Deprecated public double getCarrierPhaseUncertainty();
+    method @FloatRange(from=0, to=63) public double getCn0DbHz();
+    method @NonNull public String getCodeType();
+    method public int getConstellationType();
+    method public double getFullInterSignalBiasNanos();
+    method @FloatRange(from=0.0) public double getFullInterSignalBiasUncertaintyNanos();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
+    method public double getSatelliteInterSignalBiasNanos();
+    method @FloatRange(from=0.0) public double getSatelliteInterSignalBiasUncertaintyNanos();
+    method public double getSnrInDb();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
+    method @Deprecated public boolean hasAutomaticGainControlLevelDb();
+    method public boolean hasBasebandCn0DbHz();
+    method @Deprecated public boolean hasCarrierCycles();
+    method public boolean hasCarrierFrequencyHz();
+    method @Deprecated public boolean hasCarrierPhase();
+    method @Deprecated public boolean hasCarrierPhaseUncertainty();
+    method public boolean hasCodeType();
+    method public boolean hasFullInterSignalBiasNanos();
+    method public boolean hasFullInterSignalBiasUncertaintyNanos();
+    method public boolean hasSatelliteInterSignalBiasNanos();
+    method public boolean hasSatelliteInterSignalBiasUncertaintyNanos();
+    method public boolean hasSnrInDb();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_HALF_CYCLE_REPORTED = 16; // 0x10
+    field public static final int ADR_STATE_HALF_CYCLE_RESOLVED = 8; // 0x8
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_2ND_CODE_LOCK = 65536; // 0x10000
+    field public static final int STATE_BDS_D2_BIT_SYNC = 256; // 0x100
+    field public static final int STATE_BDS_D2_SUBFRAME_SYNC = 512; // 0x200
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_GAL_E1BC_CODE_LOCK = 1024; // 0x400
+    field public static final int STATE_GAL_E1B_PAGE_SYNC = 4096; // 0x1000
+    field public static final int STATE_GAL_E1C_2ND_CODE_LOCK = 2048; // 0x800
+    field public static final int STATE_GLO_STRING_SYNC = 64; // 0x40
+    field public static final int STATE_GLO_TOD_DECODED = 128; // 0x80
+    field public static final int STATE_GLO_TOD_KNOWN = 32768; // 0x8000
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SBAS_SYNC = 8192; // 0x2000
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_SYMBOL_SYNC = 32; // 0x20
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_TOW_KNOWN = 16384; // 0x4000
+    field public static final int STATE_UNKNOWN = 0; // 0x0
+  }
+
+  public final class GnssMeasurementRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public int getIntervalMillis();
+    method public boolean isFullTracking();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
+    field public static final int PASSIVE_INTERVAL = 2147483647; // 0x7fffffff
+  }
+
+  public static final class GnssMeasurementRequest.Builder {
+    ctor public GnssMeasurementRequest.Builder();
+    ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
+    method @NonNull public android.location.GnssMeasurementRequest build();
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setIntervalMillis(@IntRange(from=0) int);
+  }
+
+  public final class GnssMeasurementsEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.location.GnssClock getClock();
+    method @NonNull public java.util.Collection<android.location.GnssAutomaticGainControl> getGnssAutomaticGainControls();
+    method @NonNull public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
+    method public boolean hasIsFullTracking();
+    method public boolean isFullTracking();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
+  }
+
+  public static final class GnssMeasurementsEvent.Builder {
+    ctor public GnssMeasurementsEvent.Builder();
+    ctor public GnssMeasurementsEvent.Builder(@NonNull android.location.GnssMeasurementsEvent);
+    method @NonNull public android.location.GnssMeasurementsEvent build();
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder clearIsFullTracking();
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setClock(@NonNull android.location.GnssClock);
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setGnssAutomaticGainControls(@NonNull java.util.Collection<android.location.GnssAutomaticGainControl>);
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setIsFullTracking(boolean);
+    method @NonNull public android.location.GnssMeasurementsEvent.Builder setMeasurements(@NonNull java.util.Collection<android.location.GnssMeasurement>);
+  }
+
+  public abstract static class GnssMeasurementsEvent.Callback {
+    ctor public GnssMeasurementsEvent.Callback();
+    method public void onGnssMeasurementsReceived(android.location.GnssMeasurementsEvent);
+    method @Deprecated public void onStatusChanged(int);
+    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
+    field @Deprecated public static final int STATUS_NOT_ALLOWED = 3; // 0x3
+    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field @Deprecated public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public final class GnssNavigationMessage implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public byte[] getData();
+    method @IntRange(from=0xffffffff, to=120) public int getMessageId();
+    method public int getStatus();
+    method @IntRange(from=1) public int getSubmessageId();
+    method @IntRange(from=1, to=200) public int getSvid();
+    method public int getType();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_CNAV1 = 1283; // 0x503
+    field public static final int TYPE_BDS_CNAV2 = 1284; // 0x504
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_IRN_L5CA = 1793; // 0x701
+    field public static final int TYPE_QZS_L1CA = 1025; // 0x401
+    field public static final int TYPE_SBS = 513; // 0x201
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract static class GnssNavigationMessage.Callback {
+    ctor public GnssNavigationMessage.Callback();
+    method public void onGnssNavigationMessageReceived(android.location.GnssNavigationMessage);
+    method @Deprecated public void onStatusChanged(int);
+    field @Deprecated public static final int STATUS_LOCATION_DISABLED = 2; // 0x2
+    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field @Deprecated public static final int STATUS_READY = 1; // 0x1
+  }
+
+  public final class GnssSignalType implements android.os.Parcelable {
+    method @NonNull public static android.location.GnssSignalType create(int, @FloatRange(from=0.0f, fromInclusive=false) double, @NonNull String);
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getCarrierFrequencyHz();
+    method @NonNull public String getCodeType();
+    method public int getConstellationType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssSignalType> CREATOR;
+  }
+
+  public final class GnssStatus implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public float getBasebandCn0DbHz(@IntRange(from=0) int);
+    method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
+    method public int getConstellationType(@IntRange(from=0) int);
+    method @FloatRange(from=0xffffffa6, to=90) public float getElevationDegrees(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getSatelliteCount();
+    method @IntRange(from=1, to=206) public int getSvid(@IntRange(from=0) int);
+    method public boolean hasAlmanacData(@IntRange(from=0) int);
+    method public boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+    method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+    method public boolean hasEphemerisData(@IntRange(from=0) int);
+    method public boolean usedInFix(@IntRange(from=0) int);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssStatus> CREATOR;
+  }
+
+  public static final class GnssStatus.Builder {
+    ctor public GnssStatus.Builder();
+    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float, boolean, @FloatRange(from=0, to=63) float);
+    method @NonNull public android.location.GnssStatus build();
+    method @NonNull public android.location.GnssStatus.Builder clearSatellites();
+  }
+
+  public abstract static class GnssStatus.Callback {
+    ctor public GnssStatus.Callback();
+    method public void onFirstFix(int);
+    method public void onSatelliteStatusChanged(@NonNull android.location.GnssStatus);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  @Deprecated public final class GpsSatellite {
+    method @Deprecated public float getAzimuth();
+    method @Deprecated public float getElevation();
+    method @Deprecated public int getPrn();
+    method @Deprecated public float getSnr();
+    method @Deprecated public boolean hasAlmanac();
+    method @Deprecated public boolean hasEphemeris();
+    method @Deprecated public boolean usedInFix();
+  }
+
+  @Deprecated public final class GpsStatus {
+    method @Deprecated @NonNull public static android.location.GpsStatus create(@NonNull android.location.GnssStatus, int);
+    method @Deprecated public int getMaxSatellites();
+    method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
+    method @Deprecated public int getTimeToFirstFix();
+    field @Deprecated public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
+    field @Deprecated public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
+    field @Deprecated public static final int GPS_EVENT_STARTED = 1; // 0x1
+    field @Deprecated public static final int GPS_EVENT_STOPPED = 2; // 0x2
+  }
+
+  @Deprecated public static interface GpsStatus.Listener {
+    method @Deprecated public void onGpsStatusChanged(int);
+  }
+
+  @Deprecated public static interface GpsStatus.NmeaListener {
+    method @Deprecated public void onNmeaReceived(long, String);
+  }
+
+  public interface LocationListener {
+    method public default void onFlushComplete(int);
+    method public void onLocationChanged(@NonNull android.location.Location);
+    method public default void onLocationChanged(@NonNull java.util.List<android.location.Location>);
+    method public default void onProviderDisabled(@NonNull String);
+    method public default void onProviderEnabled(@NonNull String);
+    method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
+  }
+
+  public class LocationManager {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.OnNmeaMessageListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
+    method public void addTestProvider(@NonNull String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
+    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties);
+    method public void addTestProvider(@NonNull String, @NonNull android.location.provider.ProviderProperties, @NonNull java.util.Set<java.lang.String>);
+    method @Deprecated public void clearTestProviderEnabled(@NonNull String);
+    method @Deprecated public void clearTestProviderLocation(@NonNull String);
+    method @Deprecated public void clearTestProviderStatus(@NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getAllProviders();
+    method @Deprecated @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull String, @NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @Nullable public java.util.List<android.location.GnssAntennaInfo> getGnssAntennaInfos();
+    method @NonNull public android.location.GnssCapabilities getGnssCapabilities();
+    method @Nullable public String getGnssHardwareModelName();
+    method public int getGnssYearOfHardware();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
+    method @Deprecated @Nullable public android.location.LocationProvider getProvider(@NonNull String);
+    method @Nullable public android.location.provider.ProviderProperties getProviderProperties(@NonNull String);
+    method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
+    method @Deprecated @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
+    method public boolean hasProvider(@NonNull String);
+    method public boolean isLocationEnabled();
+    method public boolean isProviderEnabled(@NonNull String);
+    method public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssStatus.Callback);
+    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
+    method @Deprecated public void removeNmeaListener(@NonNull android.location.GpsStatus.NmeaListener);
+    method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
+    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
+    method public void removeTestProvider(@NonNull String);
+    method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
+    method public void removeUpdates(@NonNull android.app.PendingIntent);
+    method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
+    method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, @NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+    method public boolean sendExtraCommand(@NonNull String, @NonNull String, @Nullable android.os.Bundle);
+    method public void setTestProviderEnabled(@NonNull String, boolean);
+    method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
+    method @Deprecated public void setTestProviderStatus(@NonNull String, int, @Nullable android.os.Bundle, long);
+    method public void unregisterAntennaInfoListener(@NonNull android.location.GnssAntennaInfo.Listener);
+    method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
+    method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+    field public static final String ACTION_GNSS_CAPABILITIES_CHANGED = "android.location.action.GNSS_CAPABILITIES_CHANGED";
+    field public static final String EXTRA_GNSS_CAPABILITIES = "android.location.extra.GNSS_CAPABILITIES";
+    field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
+    field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
+    field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
+    field public static final String FUSED_PROVIDER = "fused";
+    field public static final String GPS_PROVIDER = "gps";
+    field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
+    field public static final String KEY_LOCATIONS = "locations";
+    field public static final String KEY_LOCATION_CHANGED = "location";
+    field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
+    field public static final String KEY_PROXIMITY_ENTERING = "entering";
+    field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
+    field public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
+    field public static final String NETWORK_PROVIDER = "network";
+    field public static final String PASSIVE_PROVIDER = "passive";
+    field public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
+  }
+
+  @Deprecated public class LocationProvider {
+    method @Deprecated public int getAccuracy();
+    method @Deprecated public String getName();
+    method @Deprecated public int getPowerRequirement();
+    method @Deprecated public boolean hasMonetaryCost();
+    method @Deprecated public boolean meetsCriteria(android.location.Criteria);
+    method @Deprecated public boolean requiresCell();
+    method @Deprecated public boolean requiresNetwork();
+    method @Deprecated public boolean requiresSatellite();
+    method @Deprecated public boolean supportsAltitude();
+    method @Deprecated public boolean supportsBearing();
+    method @Deprecated public boolean supportsSpeed();
+    field @Deprecated public static final int AVAILABLE = 2; // 0x2
+    field @Deprecated public static final int OUT_OF_SERVICE = 0; // 0x0
+    field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
+  }
+
+  public final class LocationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=1) public long getDurationMillis();
+    method @IntRange(from=0) public long getIntervalMillis();
+    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+    method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
+    method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
+    method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+    method public int getQuality();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
+    field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+    field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+    field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+    field public static final int QUALITY_LOW_POWER = 104; // 0x68
+  }
+
+  public static final class LocationRequest.Builder {
+    ctor public LocationRequest.Builder(long);
+    ctor public LocationRequest.Builder(@NonNull android.location.LocationRequest);
+    method @NonNull public android.location.LocationRequest build();
+    method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
+    method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
+    method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
+    method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
+    method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.LocationRequest.Builder setQuality(int);
+  }
+
+  public interface OnNmeaMessageListener {
+    method public void onNmeaMessage(String, long);
+  }
+
+  public abstract class SettingInjectorService extends android.app.Service {
+    ctor public SettingInjectorService(String);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method protected abstract boolean onGetEnabled();
+    method protected abstract String onGetSummary();
+    method public final void onStart(android.content.Intent, int);
+    method public final int onStartCommand(android.content.Intent, int, int);
+    method public static final void refreshSettings(@NonNull android.content.Context);
+    field public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
+    field public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
+    field public static final String ATTRIBUTES_NAME = "injected-location-setting";
+    field public static final String META_DATA_NAME = "android.location.SettingInjectorService";
+  }
+
+}
+
+package android.location.altitude {
+
+  public final class AltitudeConverter {
+    ctor public AltitudeConverter();
+    method @WorkerThread public void addMslAltitudeToLocation(@NonNull android.content.Context, @NonNull android.location.Location) throws java.io.IOException;
+  }
+
+}
+
+package android.location.provider {
+
+  public final class ProviderProperties implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAccuracy();
+    method public int getPowerUsage();
+    method public boolean hasAltitudeSupport();
+    method public boolean hasBearingSupport();
+    method public boolean hasCellRequirement();
+    method public boolean hasMonetaryCost();
+    method public boolean hasNetworkRequirement();
+    method public boolean hasSatelliteRequirement();
+    method public boolean hasSpeedSupport();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int ACCURACY_COARSE = 2; // 0x2
+    field public static final int ACCURACY_FINE = 1; // 0x1
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderProperties> CREATOR;
+    field public static final int POWER_USAGE_HIGH = 3; // 0x3
+    field public static final int POWER_USAGE_LOW = 1; // 0x1
+    field public static final int POWER_USAGE_MEDIUM = 2; // 0x2
+  }
+
+  public static final class ProviderProperties.Builder {
+    ctor public ProviderProperties.Builder();
+    ctor public ProviderProperties.Builder(@NonNull android.location.provider.ProviderProperties);
+    method @NonNull public android.location.provider.ProviderProperties build();
+    method @NonNull public android.location.provider.ProviderProperties.Builder setAccuracy(int);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasAltitudeSupport(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasBearingSupport(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasCellRequirement(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasMonetaryCost(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasNetworkRequirement(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSatelliteRequirement(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setHasSpeedSupport(boolean);
+    method @NonNull public android.location.provider.ProviderProperties.Builder setPowerUsage(int);
+  }
+
+}
+
diff --git a/location/api/module-lib-current.txt b/location/api/module-lib-current.txt
index d802177..8c14b864 100644
--- a/location/api/module-lib-current.txt
+++ b/location/api/module-lib-current.txt
@@ -1 +1,11 @@
 // Signature format: 2.0
+package android.location {
+
+  public class LocationManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public boolean injectLocation(@NonNull android.location.Location);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public boolean isAutomotiveGnssSuspended();
+    method @RequiresPermission(android.Manifest.permission.CONTROL_AUTOMOTIVE_GNSS) public void setAutomotiveGnssSuspended(boolean);
+  }
+
+}
+
diff --git a/location/api/module-lib-lint-baseline.txt b/location/api/module-lib-lint-baseline.txt
new file mode 100644
index 0000000..7cd6a86
--- /dev/null
+++ b/location/api/module-lib-lint-baseline.txt
@@ -0,0 +1,13 @@
+// Baseline format: 1.0
+SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index d802177..a1d6ab5 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -1 +1,646 @@
 // Signature format: 2.0
+package android.location {
+
+  public abstract class BatchedLocationCallback {
+    ctor public BatchedLocationCallback();
+    method public void onLocationBatch(java.util.List<android.location.Location>);
+  }
+
+  public final class CorrelationVector implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond();
+    method @NonNull public int[] getMagnitude();
+    method @FloatRange(from=0.0f) public double getSamplingStartMeters();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getSamplingWidthMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.CorrelationVector> CREATOR;
+  }
+
+  public static final class CorrelationVector.Builder {
+    ctor public CorrelationVector.Builder();
+    method @NonNull public android.location.CorrelationVector build();
+    method @NonNull public android.location.CorrelationVector.Builder setFrequencyOffsetMetersPerSecond(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.CorrelationVector.Builder setMagnitude(@NonNull int[]);
+    method @NonNull public android.location.CorrelationVector.Builder setSamplingStartMeters(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.CorrelationVector.Builder setSamplingWidthMeters(@FloatRange(from=0.0f, fromInclusive=false) double);
+  }
+
+  public final class Country implements android.os.Parcelable {
+    ctor public Country(@NonNull String, int);
+    method public int describeContents();
+    method @NonNull public String getCountryCode();
+    method public int getSource();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int COUNTRY_SOURCE_LOCALE = 3; // 0x3
+    field public static final int COUNTRY_SOURCE_LOCATION = 1; // 0x1
+    field public static final int COUNTRY_SOURCE_NETWORK = 0; // 0x0
+    field public static final int COUNTRY_SOURCE_SIM = 2; // 0x2
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.Country> CREATOR;
+  }
+
+  public class CountryDetector {
+    method public void registerCountryDetectorCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Country>);
+    method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer<android.location.Country>);
+  }
+
+  public final class GnssCapabilities implements android.os.Parcelable {
+    method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane();
+    method @Deprecated public boolean hasNavMessages();
+    method @Deprecated public boolean hasSatelliteBlacklist();
+  }
+
+  public final class GnssExcessPathInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f) public float getAttenuationDb();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssReflectingPlane getReflectingPlane();
+    method public boolean hasAttenuation();
+    method public boolean hasExcessPathLength();
+    method public boolean hasExcessPathLengthUncertainty();
+    method public boolean hasReflectingPlane();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssExcessPathInfo> CREATOR;
+  }
+
+  public static final class GnssExcessPathInfo.Builder {
+    ctor public GnssExcessPathInfo.Builder();
+    method @NonNull public android.location.GnssExcessPathInfo build();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearAttenuationDb();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setAttenuationDb(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssExcessPathInfo.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+  }
+
+  public final class GnssMeasurement implements android.os.Parcelable {
+    method @Nullable public java.util.Collection<android.location.CorrelationVector> getCorrelationVectors();
+    method @Nullable public android.location.SatellitePvt getSatellitePvt();
+    method public boolean hasCorrelationVectors();
+    method public boolean hasSatellitePvt();
+  }
+
+  public final class GnssMeasurementCorrections implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
+    method @FloatRange(from=0.0f, to=360.0f) public float getEnvironmentBearingDegrees();
+    method @FloatRange(from=0.0f, to=180.0f) public float getEnvironmentBearingUncertaintyDegrees();
+    method @FloatRange(from=0.0f) public double getHorizontalPositionUncertaintyMeters();
+    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
+    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
+    method @NonNull public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList();
+    method @IntRange(from=0) public long getToaGpsNanosecondsOfWeek();
+    method @FloatRange(from=0.0f) public double getVerticalPositionUncertaintyMeters();
+    method public boolean hasEnvironmentBearing();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
+  }
+
+  public static final class GnssMeasurementCorrections.Builder {
+    ctor public GnssMeasurementCorrections.Builder();
+    method @NonNull public android.location.GnssMeasurementCorrections build();
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingDegrees(@FloatRange(from=0.0f, to=360.0f) float);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingUncertaintyDegrees(@FloatRange(from=0.0f, to=180.0f) float);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setSingleSatelliteCorrectionList(@NonNull java.util.List<android.location.GnssSingleSatCorrection>);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(@IntRange(from=0) long);
+    method @NonNull public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
+  }
+
+  public final class GnssMeasurementRequest implements android.os.Parcelable {
+    method @NonNull public android.os.WorkSource getWorkSource();
+    method public boolean isCorrelationVectorOutputsEnabled();
+  }
+
+  public static final class GnssMeasurementRequest.Builder {
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setCorrelationVectorOutputsEnabled(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.GnssMeasurementRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
+  }
+
+  public final class GnssReflectingPlane implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
+    method @FloatRange(from=0.0f, to=360.0f) public double getAzimuthDegrees();
+    method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
+    method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GnssReflectingPlane> CREATOR;
+  }
+
+  public static final class GnssReflectingPlane.Builder {
+    ctor public GnssReflectingPlane.Builder();
+    method @NonNull public android.location.GnssReflectingPlane build();
+    method @NonNull public android.location.GnssReflectingPlane.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
+    method @NonNull public android.location.GnssReflectingPlane.Builder setAzimuthDegrees(@FloatRange(from=0.0f, to=360.0f) double);
+    method @NonNull public android.location.GnssReflectingPlane.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
+    method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
+  }
+
+  public final class GnssRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isFullTracking();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR;
+  }
+
+  public static final class GnssRequest.Builder {
+    ctor public GnssRequest.Builder();
+    ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest);
+    method @NonNull public android.location.GnssRequest build();
+    method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean);
+  }
+
+  public final class GnssSingleSatCorrection implements android.os.Parcelable {
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
+    method @FloatRange(from=0.0f) public float getCombinedAttenuationDb();
+    method public int getConstellationType();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
+    method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
+    method @NonNull public java.util.List<android.location.GnssExcessPathInfo> getGnssExcessPathInfoList();
+    method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
+    method @Deprecated @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
+    method @IntRange(from=0) public int getSatelliteId();
+    method public boolean hasCombinedAttenuation();
+    method public boolean hasExcessPathLength();
+    method public boolean hasExcessPathLengthUncertainty();
+    method @Deprecated public boolean hasReflectingPlane();
+    method public boolean hasValidSatelliteLineOfSight();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
+  }
+
+  public static final class GnssSingleSatCorrection.Builder {
+    ctor public GnssSingleSatCorrection.Builder();
+    method @NonNull public android.location.GnssSingleSatCorrection build();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearCombinedAttenuationDb();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthMeters();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearExcessPathLengthUncertaintyMeters();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder clearProbabilityLineOfSight();
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setCombinedAttenuationDb(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setGnssExcessPathInfoList(@NonNull java.util.List<android.location.GnssExcessPathInfo>);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
+    method @Deprecated @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
+    method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
+  }
+
+  @Deprecated public class GpsClock implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated public double getBiasInNs();
+    method @Deprecated public double getBiasUncertaintyInNs();
+    method @Deprecated public double getDriftInNsPerSec();
+    method @Deprecated public double getDriftUncertaintyInNsPerSec();
+    method @Deprecated public long getFullBiasInNs();
+    method @Deprecated public short getLeapSecond();
+    method @Deprecated public long getTimeInNs();
+    method @Deprecated public double getTimeUncertaintyInNs();
+    method @Deprecated public byte getType();
+    method @Deprecated public boolean hasBiasInNs();
+    method @Deprecated public boolean hasBiasUncertaintyInNs();
+    method @Deprecated public boolean hasDriftInNsPerSec();
+    method @Deprecated public boolean hasDriftUncertaintyInNsPerSec();
+    method @Deprecated public boolean hasFullBiasInNs();
+    method @Deprecated public boolean hasLeapSecond();
+    method @Deprecated public boolean hasTimeUncertaintyInNs();
+    method @Deprecated public void reset();
+    method @Deprecated public void resetBiasInNs();
+    method @Deprecated public void resetBiasUncertaintyInNs();
+    method @Deprecated public void resetDriftInNsPerSec();
+    method @Deprecated public void resetDriftUncertaintyInNsPerSec();
+    method @Deprecated public void resetFullBiasInNs();
+    method @Deprecated public void resetLeapSecond();
+    method @Deprecated public void resetTimeUncertaintyInNs();
+    method @Deprecated public void set(android.location.GpsClock);
+    method @Deprecated public void setBiasInNs(double);
+    method @Deprecated public void setBiasUncertaintyInNs(double);
+    method @Deprecated public void setDriftInNsPerSec(double);
+    method @Deprecated public void setDriftUncertaintyInNsPerSec(double);
+    method @Deprecated public void setFullBiasInNs(long);
+    method @Deprecated public void setLeapSecond(short);
+    method @Deprecated public void setTimeInNs(long);
+    method @Deprecated public void setTimeUncertaintyInNs(double);
+    method @Deprecated public void setType(byte);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
+    field @Deprecated public static final byte TYPE_GPS_TIME = 2; // 0x2
+    field @Deprecated public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
+    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  @Deprecated public class GpsMeasurement implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated public double getAccumulatedDeltaRangeInMeters();
+    method @Deprecated public short getAccumulatedDeltaRangeState();
+    method @Deprecated public double getAccumulatedDeltaRangeUncertaintyInMeters();
+    method @Deprecated public double getAzimuthInDeg();
+    method @Deprecated public double getAzimuthUncertaintyInDeg();
+    method @Deprecated public int getBitNumber();
+    method @Deprecated public long getCarrierCycles();
+    method @Deprecated public float getCarrierFrequencyInHz();
+    method @Deprecated public double getCarrierPhase();
+    method @Deprecated public double getCarrierPhaseUncertainty();
+    method @Deprecated public double getCn0InDbHz();
+    method @Deprecated public double getCodePhaseInChips();
+    method @Deprecated public double getCodePhaseUncertaintyInChips();
+    method @Deprecated public double getDopplerShiftInHz();
+    method @Deprecated public double getDopplerShiftUncertaintyInHz();
+    method @Deprecated public double getElevationInDeg();
+    method @Deprecated public double getElevationUncertaintyInDeg();
+    method @Deprecated public byte getLossOfLock();
+    method @Deprecated public byte getMultipathIndicator();
+    method @Deprecated public byte getPrn();
+    method @Deprecated public double getPseudorangeInMeters();
+    method @Deprecated public double getPseudorangeRateInMetersPerSec();
+    method @Deprecated public double getPseudorangeRateUncertaintyInMetersPerSec();
+    method @Deprecated public double getPseudorangeUncertaintyInMeters();
+    method @Deprecated public long getReceivedGpsTowInNs();
+    method @Deprecated public long getReceivedGpsTowUncertaintyInNs();
+    method @Deprecated public double getSnrInDb();
+    method @Deprecated public short getState();
+    method @Deprecated public short getTimeFromLastBitInMs();
+    method @Deprecated public double getTimeOffsetInNs();
+    method @Deprecated public boolean hasAzimuthInDeg();
+    method @Deprecated public boolean hasAzimuthUncertaintyInDeg();
+    method @Deprecated public boolean hasBitNumber();
+    method @Deprecated public boolean hasCarrierCycles();
+    method @Deprecated public boolean hasCarrierFrequencyInHz();
+    method @Deprecated public boolean hasCarrierPhase();
+    method @Deprecated public boolean hasCarrierPhaseUncertainty();
+    method @Deprecated public boolean hasCodePhaseInChips();
+    method @Deprecated public boolean hasCodePhaseUncertaintyInChips();
+    method @Deprecated public boolean hasDopplerShiftInHz();
+    method @Deprecated public boolean hasDopplerShiftUncertaintyInHz();
+    method @Deprecated public boolean hasElevationInDeg();
+    method @Deprecated public boolean hasElevationUncertaintyInDeg();
+    method @Deprecated public boolean hasPseudorangeInMeters();
+    method @Deprecated public boolean hasPseudorangeUncertaintyInMeters();
+    method @Deprecated public boolean hasSnrInDb();
+    method @Deprecated public boolean hasTimeFromLastBitInMs();
+    method @Deprecated public boolean isPseudorangeRateCorrected();
+    method @Deprecated public boolean isUsedInFix();
+    method @Deprecated public void reset();
+    method @Deprecated public void resetAzimuthInDeg();
+    method @Deprecated public void resetAzimuthUncertaintyInDeg();
+    method @Deprecated public void resetBitNumber();
+    method @Deprecated public void resetCarrierCycles();
+    method @Deprecated public void resetCarrierFrequencyInHz();
+    method @Deprecated public void resetCarrierPhase();
+    method @Deprecated public void resetCarrierPhaseUncertainty();
+    method @Deprecated public void resetCodePhaseInChips();
+    method @Deprecated public void resetCodePhaseUncertaintyInChips();
+    method @Deprecated public void resetDopplerShiftInHz();
+    method @Deprecated public void resetDopplerShiftUncertaintyInHz();
+    method @Deprecated public void resetElevationInDeg();
+    method @Deprecated public void resetElevationUncertaintyInDeg();
+    method @Deprecated public void resetPseudorangeInMeters();
+    method @Deprecated public void resetPseudorangeUncertaintyInMeters();
+    method @Deprecated public void resetSnrInDb();
+    method @Deprecated public void resetTimeFromLastBitInMs();
+    method @Deprecated public void set(android.location.GpsMeasurement);
+    method @Deprecated public void setAccumulatedDeltaRangeInMeters(double);
+    method @Deprecated public void setAccumulatedDeltaRangeState(short);
+    method @Deprecated public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
+    method @Deprecated public void setAzimuthInDeg(double);
+    method @Deprecated public void setAzimuthUncertaintyInDeg(double);
+    method @Deprecated public void setBitNumber(int);
+    method @Deprecated public void setCarrierCycles(long);
+    method @Deprecated public void setCarrierFrequencyInHz(float);
+    method @Deprecated public void setCarrierPhase(double);
+    method @Deprecated public void setCarrierPhaseUncertainty(double);
+    method @Deprecated public void setCn0InDbHz(double);
+    method @Deprecated public void setCodePhaseInChips(double);
+    method @Deprecated public void setCodePhaseUncertaintyInChips(double);
+    method @Deprecated public void setDopplerShiftInHz(double);
+    method @Deprecated public void setDopplerShiftUncertaintyInHz(double);
+    method @Deprecated public void setElevationInDeg(double);
+    method @Deprecated public void setElevationUncertaintyInDeg(double);
+    method @Deprecated public void setLossOfLock(byte);
+    method @Deprecated public void setMultipathIndicator(byte);
+    method @Deprecated public void setPrn(byte);
+    method @Deprecated public void setPseudorangeInMeters(double);
+    method @Deprecated public void setPseudorangeRateInMetersPerSec(double);
+    method @Deprecated public void setPseudorangeRateUncertaintyInMetersPerSec(double);
+    method @Deprecated public void setPseudorangeUncertaintyInMeters(double);
+    method @Deprecated public void setReceivedGpsTowInNs(long);
+    method @Deprecated public void setReceivedGpsTowUncertaintyInNs(long);
+    method @Deprecated public void setSnrInDb(double);
+    method @Deprecated public void setState(short);
+    method @Deprecated public void setTimeFromLastBitInMs(short);
+    method @Deprecated public void setTimeOffsetInNs(double);
+    method @Deprecated public void setUsedInFix(boolean);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field @Deprecated public static final short ADR_STATE_RESET = 2; // 0x2
+    field @Deprecated public static final short ADR_STATE_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final short ADR_STATE_VALID = 1; // 0x1
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
+    field @Deprecated public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
+    field @Deprecated public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
+    field @Deprecated public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field @Deprecated public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field @Deprecated public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final short STATE_BIT_SYNC = 2; // 0x2
+    field @Deprecated public static final short STATE_CODE_LOCK = 1; // 0x1
+    field @Deprecated public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field @Deprecated public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
+    field @Deprecated public static final short STATE_TOW_DECODED = 8; // 0x8
+    field @Deprecated public static final short STATE_UNKNOWN = 0; // 0x0
+  }
+
+  @Deprecated public class GpsMeasurementsEvent implements android.os.Parcelable {
+    ctor @Deprecated public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.location.GpsClock getClock();
+    method @Deprecated @NonNull public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
+    field @Deprecated public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
+    field @Deprecated public static final int STATUS_READY = 1; // 0x1
+  }
+
+  @Deprecated public static interface GpsMeasurementsEvent.Listener {
+    method @Deprecated public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
+    method @Deprecated public void onStatusChanged(int);
+  }
+
+  @Deprecated public class GpsNavigationMessage implements android.os.Parcelable {
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public byte[] getData();
+    method @Deprecated public short getMessageId();
+    method @Deprecated public byte getPrn();
+    method @Deprecated public short getStatus();
+    method @Deprecated public short getSubmessageId();
+    method @Deprecated public byte getType();
+    method @Deprecated public void reset();
+    method @Deprecated public void set(android.location.GpsNavigationMessage);
+    method @Deprecated public void setData(byte[]);
+    method @Deprecated public void setMessageId(short);
+    method @Deprecated public void setPrn(byte);
+    method @Deprecated public void setStatus(short);
+    method @Deprecated public void setSubmessageId(short);
+    method @Deprecated public void setType(byte);
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
+    field @Deprecated public static final short STATUS_PARITY_PASSED = 1; // 0x1
+    field @Deprecated public static final short STATUS_PARITY_REBUILT = 2; // 0x2
+    field @Deprecated public static final short STATUS_UNKNOWN = 0; // 0x0
+    field @Deprecated public static final byte TYPE_CNAV2 = 4; // 0x4
+    field @Deprecated public static final byte TYPE_L1CA = 1; // 0x1
+    field @Deprecated public static final byte TYPE_L2CNAV = 2; // 0x2
+    field @Deprecated public static final byte TYPE_L5CNAV = 3; // 0x3
+    field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
+  }
+
+  @Deprecated public class GpsNavigationMessageEvent implements android.os.Parcelable {
+    ctor @Deprecated public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.location.GpsNavigationMessage getNavigationMessage();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
+    field @Deprecated public static int STATUS_GPS_LOCATION_DISABLED;
+    field @Deprecated public static int STATUS_NOT_SUPPORTED;
+    field @Deprecated public static int STATUS_READY;
+  }
+
+  @Deprecated public static interface GpsNavigationMessageEvent.Listener {
+    method @Deprecated public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
+    method @Deprecated public void onStatusChanged(int);
+  }
+
+  public final class LastLocationRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isAdasGnssBypass();
+    method public boolean isHiddenFromAppOps();
+    method public boolean isLocationSettingsIgnored();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.LastLocationRequest> CREATOR;
+  }
+
+  public static final class LastLocationRequest.Builder {
+    ctor public LastLocationRequest.Builder();
+    ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest);
+    method @NonNull public android.location.LastLocationRequest build();
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean);
+  }
+
+  public class LocationManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
+    method @Nullable public String getExtraLocationControllerPackage();
+    method @Deprecated public int getGnssBatchSize();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String, @NonNull android.location.LastLocationRequest);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
+    method public boolean isAdasGnssLocationEnabled();
+    method public boolean isExtraLocationControllerPackageEnabled();
+    method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
+    method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
+    method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void removeProviderRequestChangedListener(@NonNull android.location.provider.ProviderRequest.ChangedListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public void setAdasGnssLocationEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+    field public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED = "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
+    field public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
+    field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public static final String GPS_HARDWARE_PROVIDER = "gps_hardware";
+  }
+
+  public final class LocationRequest implements android.os.Parcelable {
+    method @Deprecated @NonNull public static android.location.LocationRequest create();
+    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
+    method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
+    method @Deprecated public long getExpireAt();
+    method @Deprecated public long getExpireIn();
+    method @Deprecated public long getFastestInterval();
+    method @Deprecated public boolean getHideFromAppOps();
+    method @Deprecated public long getInterval();
+    method @Deprecated public int getNumUpdates();
+    method @Deprecated @NonNull public String getProvider();
+    method @Deprecated public float getSmallestDisplacement();
+    method @NonNull public android.os.WorkSource getWorkSource();
+    method public boolean isAdasGnssBypass();
+    method public boolean isHiddenFromAppOps();
+    method public boolean isLocationSettingsIgnored();
+    method public boolean isLowPower();
+    method @Deprecated public boolean isLowPowerMode();
+    method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
+    method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
+    method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
+    method @Deprecated public void setHideFromAppOps(boolean);
+    method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
+    method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
+    method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
+    method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
+    method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
+    method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
+    method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
+    field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+    field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+    field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+    field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+    field @Deprecated public static final int POWER_LOW = 201; // 0xc9
+    field @Deprecated public static final int POWER_NONE = 200; // 0xc8
+  }
+
+  public static final class LocationRequest.Builder {
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
+    method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
+  }
+
+  public final class SatellitePvt implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo();
+    method public int getEphemerisSource();
+    method @FloatRange public double getIonoDelayMeters();
+    method @IntRange(from=0, to=1023) public int getIssueOfDataClock();
+    method @IntRange(from=0, to=1023) public int getIssueOfDataEphemeris();
+    method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef();
+    method @IntRange(from=0) public long getTimeOfClockSeconds();
+    method @IntRange(from=0) public long getTimeOfEphemerisSeconds();
+    method @FloatRange public double getTropoDelayMeters();
+    method @Nullable public android.location.SatellitePvt.VelocityEcef getVelocityEcef();
+    method public boolean hasIono();
+    method public boolean hasIssueOfDataClock();
+    method public boolean hasIssueOfDataEphemeris();
+    method public boolean hasPositionVelocityClockInfo();
+    method public boolean hasTimeOfClockSeconds();
+    method public boolean hasTimeOfEphemerisSeconds();
+    method public boolean hasTropo();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt> CREATOR;
+    field public static final int EPHEMERIS_SOURCE_DEMODULATED = 0; // 0x0
+    field public static final int EPHEMERIS_SOURCE_OTHER = 3; // 0x3
+    field public static final int EPHEMERIS_SOURCE_SERVER_LONG_TERM = 2; // 0x2
+    field public static final int EPHEMERIS_SOURCE_SERVER_NORMAL = 1; // 0x1
+  }
+
+  public static final class SatellitePvt.Builder {
+    ctor public SatellitePvt.Builder();
+    method @NonNull public android.location.SatellitePvt build();
+    method @NonNull public android.location.SatellitePvt.Builder setClockInfo(@NonNull android.location.SatellitePvt.ClockInfo);
+    method @NonNull public android.location.SatellitePvt.Builder setEphemerisSource(int);
+    method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
+    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataClock(@IntRange(from=0, to=1023) int);
+    method @NonNull public android.location.SatellitePvt.Builder setIssueOfDataEphemeris(@IntRange(from=0, to=1023) int);
+    method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef);
+    method @NonNull public android.location.SatellitePvt.Builder setTimeOfClockSeconds(@IntRange(from=0) long);
+    method @NonNull public android.location.SatellitePvt.Builder setTimeOfEphemerisSeconds(@IntRange(from=0) long);
+    method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
+    method @NonNull public android.location.SatellitePvt.Builder setVelocityEcef(@NonNull android.location.SatellitePvt.VelocityEcef);
+  }
+
+  public static final class SatellitePvt.ClockInfo implements android.os.Parcelable {
+    ctor public SatellitePvt.ClockInfo(double, double, double);
+    method public int describeContents();
+    method @FloatRange public double getClockDriftMetersPerSecond();
+    method @FloatRange public double getHardwareCodeBiasMeters();
+    method @FloatRange public double getTimeCorrectionMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.ClockInfo> CREATOR;
+  }
+
+  public static final class SatellitePvt.PositionEcef implements android.os.Parcelable {
+    ctor public SatellitePvt.PositionEcef(double, double, double, double);
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreMeters();
+    method @FloatRange public double getXMeters();
+    method @FloatRange public double getYMeters();
+    method @FloatRange public double getZMeters();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.PositionEcef> CREATOR;
+  }
+
+  public static final class SatellitePvt.VelocityEcef implements android.os.Parcelable {
+    ctor public SatellitePvt.VelocityEcef(double, double, double, double);
+    method public int describeContents();
+    method @FloatRange(from=0.0f, fromInclusive=false) public double getUreRateMetersPerSecond();
+    method @FloatRange public double getXMetersPerSecond();
+    method @FloatRange public double getYMetersPerSecond();
+    method @FloatRange public double getZMetersPerSecond();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.VelocityEcef> CREATOR;
+  }
+
+}
+
+package android.location.provider {
+
+  public abstract class LocationProviderBase {
+    ctor public LocationProviderBase(@NonNull android.content.Context, @NonNull String, @NonNull android.location.provider.ProviderProperties);
+    method @Nullable public final android.os.IBinder getBinder();
+    method @NonNull public android.location.provider.ProviderProperties getProperties();
+    method public boolean isAllowed();
+    method public abstract void onFlush(@NonNull android.location.provider.LocationProviderBase.OnFlushCompleteCallback);
+    method public abstract void onSendExtraCommand(@NonNull String, @Nullable android.os.Bundle);
+    method public abstract void onSetRequest(@NonNull android.location.provider.ProviderRequest);
+    method public void reportLocation(@NonNull android.location.Location);
+    method public void reportLocations(@NonNull java.util.List<android.location.Location>);
+    method public void setAllowed(boolean);
+    method public void setProperties(@NonNull android.location.provider.ProviderProperties);
+    field public static final String ACTION_FUSED_PROVIDER = "com.android.location.service.FusedLocationProvider";
+    field public static final String ACTION_GNSS_PROVIDER = "android.location.provider.action.GNSS_PROVIDER";
+    field public static final String ACTION_NETWORK_PROVIDER = "com.android.location.service.v3.NetworkLocationProvider";
+  }
+
+  public static interface LocationProviderBase.OnFlushCompleteCallback {
+    method public void onFlushComplete();
+  }
+
+  public final class ProviderRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=0) public long getIntervalMillis();
+    method @IntRange(from=0) public long getMaxUpdateDelayMillis();
+    method public int getQuality();
+    method @NonNull public android.os.WorkSource getWorkSource();
+    method public boolean isActive();
+    method public boolean isLocationSettingsIgnored();
+    method public boolean isLowPower();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.provider.ProviderRequest> CREATOR;
+    field @NonNull public static final android.location.provider.ProviderRequest EMPTY_REQUEST;
+    field public static final long INTERVAL_DISABLED = 9223372036854775807L; // 0x7fffffffffffffffL
+  }
+
+  public static final class ProviderRequest.Builder {
+    ctor public ProviderRequest.Builder();
+    method @NonNull public android.location.provider.ProviderRequest build();
+    method @NonNull public android.location.provider.ProviderRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setLocationSettingsIgnored(boolean);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setLowPower(boolean);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setQuality(int);
+    method @NonNull public android.location.provider.ProviderRequest.Builder setWorkSource(@NonNull android.os.WorkSource);
+  }
+
+  public static interface ProviderRequest.ChangedListener {
+    method public void onProviderRequestChanged(@NonNull String, @NonNull android.location.provider.ProviderRequest);
+  }
+
+}
+
diff --git a/location/api/system-lint-baseline.txt b/location/api/system-lint-baseline.txt
new file mode 100644
index 0000000..a5e5752
--- /dev/null
+++ b/location/api/system-lint-baseline.txt
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
+    SAM-compatible parameters (such as parameter 1, "listener", in android.location.LocationManager.addNmeaListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 4, "listener", in android.location.LocationManager.requestLocationUpdates) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
+    SAM-compatible parameters (such as parameter 2, "listener", in android.location.LocationManager.requestSingleUpdate) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/location/api/system-removed.txt b/location/api/system-removed.txt
index d802177..2755a9f 100644
--- a/location/api/system-removed.txt
+++ b/location/api/system-removed.txt
@@ -1 +1,15 @@
 // Signature format: 2.0
+package android.location {
+
+  public class LocationManager {
+    method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
+    method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
+    method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
+    method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
+  }
+
+}
+
diff --git a/location/api/test-current.txt b/location/api/test-current.txt
index d802177..bdcb00a 100644
--- a/location/api/test-current.txt
+++ b/location/api/test-current.txt
@@ -1 +1,104 @@
 // Signature format: 2.0
+package android.location {
+
+  public final class GnssClock implements android.os.Parcelable {
+    ctor public GnssClock();
+    method public void reset();
+    method public void resetBiasNanos();
+    method public void resetBiasUncertaintyNanos();
+    method public void resetDriftNanosPerSecond();
+    method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetElapsedRealtimeNanos();
+    method public void resetElapsedRealtimeUncertaintyNanos();
+    method public void resetFullBiasNanos();
+    method public void resetLeapSecond();
+    method public void resetReferenceCarrierFrequencyHzForIsb();
+    method public void resetReferenceCodeTypeForIsb();
+    method public void resetReferenceConstellationTypeForIsb();
+    method public void resetTimeUncertaintyNanos();
+    method public void set(android.location.GnssClock);
+    method public void setBiasNanos(double);
+    method public void setBiasUncertaintyNanos(@FloatRange(from=0.0f) double);
+    method public void setDriftNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(@FloatRange(from=0.0f) double);
+    method public void setElapsedRealtimeNanos(long);
+    method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0f) double);
+    method public void setFullBiasNanos(long);
+    method public void setHardwareClockDiscontinuityCount(int);
+    method public void setLeapSecond(int);
+    method public void setReferenceCarrierFrequencyHzForIsb(@FloatRange(from=0.0) double);
+    method public void setReferenceCodeTypeForIsb(@NonNull String);
+    method public void setReferenceConstellationTypeForIsb(int);
+    method public void setTimeNanos(long);
+    method public void setTimeUncertaintyNanos(@FloatRange(from=0.0f) double);
+  }
+
+  public final class GnssMeasurement implements android.os.Parcelable {
+    ctor public GnssMeasurement();
+    method public void reset();
+    method public void resetAutomaticGainControlLevel();
+    method public void resetBasebandCn0DbHz();
+    method @Deprecated public void resetCarrierCycles();
+    method public void resetCarrierFrequencyHz();
+    method @Deprecated public void resetCarrierPhase();
+    method @Deprecated public void resetCarrierPhaseUncertainty();
+    method public void resetCodeType();
+    method public void resetCorrelationVectors();
+    method public void resetFullInterSignalBiasNanos();
+    method public void resetFullInterSignalBiasUncertaintyNanos();
+    method public void resetSatelliteInterSignalBiasNanos();
+    method public void resetSatelliteInterSignalBiasUncertaintyNanos();
+    method public void resetSatellitePvt();
+    method public void resetSnrInDb();
+    method public void set(android.location.GnssMeasurement);
+    method public void setAccumulatedDeltaRangeMeters(double);
+    method public void setAccumulatedDeltaRangeState(int);
+    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
+    method @Deprecated public void setAutomaticGainControlLevelInDb(double);
+    method public void setBasebandCn0DbHz(double);
+    method @Deprecated public void setCarrierCycles(long);
+    method public void setCarrierFrequencyHz(float);
+    method @Deprecated public void setCarrierPhase(double);
+    method @Deprecated public void setCarrierPhaseUncertainty(double);
+    method public void setCn0DbHz(double);
+    method public void setCodeType(@NonNull String);
+    method public void setConstellationType(int);
+    method public void setCorrelationVectors(@Nullable java.util.Collection<android.location.CorrelationVector>);
+    method public void setFullInterSignalBiasNanos(double);
+    method public void setFullInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
+    method public void setMultipathIndicator(int);
+    method public void setPseudorangeRateMetersPerSecond(double);
+    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+    method public void setReceivedSvTimeNanos(long);
+    method public void setReceivedSvTimeUncertaintyNanos(long);
+    method public void setSatelliteInterSignalBiasNanos(double);
+    method public void setSatelliteInterSignalBiasUncertaintyNanos(@FloatRange(from=0.0) double);
+    method public void setSatellitePvt(@Nullable android.location.SatellitePvt);
+    method public void setSnrInDb(double);
+    method public void setState(int);
+    method public void setSvid(int);
+    method public void setTimeOffsetNanos(double);
+    field public static final int ADR_STATE_ALL = 31; // 0x1f
+  }
+
+  public final class GnssNavigationMessage implements android.os.Parcelable {
+    ctor public GnssNavigationMessage();
+    method public void reset();
+    method public void set(android.location.GnssNavigationMessage);
+    method public void setData(byte[]);
+    method public void setMessageId(@IntRange(from=0xffffffff, to=120) int);
+    method public void setStatus(int);
+    method public void setSubmessageId(@IntRange(from=1) int);
+    method public void setSvid(@IntRange(from=1, to=200) int);
+    method public void setType(int);
+  }
+
+  public class LocationManager {
+    method @NonNull public String[] getBackgroundThrottlingWhitelist();
+    method @NonNull public android.os.PackageTagsList getIgnoreSettingsAllowlist();
+    method @Deprecated @NonNull public String[] getIgnoreSettingsWhitelist();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
+  }
+
+}
+
diff --git a/location/api/test-lint-baseline.txt b/location/api/test-lint-baseline.txt
new file mode 100644
index 0000000..189588e
--- /dev/null
+++ b/location/api/test-lint-baseline.txt
@@ -0,0 +1,54 @@
+// Baseline format: 1.0
+GetterSetterNames: android.location.GnssClock#setBiasNanos(double):
+    Symmetric method for `hasBiasNanos` must be named `setHasBiasNanos`; was `setBiasNanos`
+GetterSetterNames: android.location.GnssClock#setBiasUncertaintyNanos(double):
+    Symmetric method for `hasBiasUncertaintyNanos` must be named `setHasBiasUncertaintyNanos`; was `setBiasUncertaintyNanos`
+GetterSetterNames: android.location.GnssClock#setDriftNanosPerSecond(double):
+    Symmetric method for `hasDriftNanosPerSecond` must be named `setHasDriftNanosPerSecond`; was `setDriftNanosPerSecond`
+GetterSetterNames: android.location.GnssClock#setDriftUncertaintyNanosPerSecond(double):
+    Symmetric method for `hasDriftUncertaintyNanosPerSecond` must be named `setHasDriftUncertaintyNanosPerSecond`; was `setDriftUncertaintyNanosPerSecond`
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeNanos(long):
+    Symmetric method for `hasElapsedRealtimeNanos` must be named `setHasElapsedRealtimeNanos`; was `setElapsedRealtimeNanos`
+GetterSetterNames: android.location.GnssClock#setElapsedRealtimeUncertaintyNanos(double):
+    Symmetric method for `hasElapsedRealtimeUncertaintyNanos` must be named `setHasElapsedRealtimeUncertaintyNanos`; was `setElapsedRealtimeUncertaintyNanos`
+GetterSetterNames: android.location.GnssClock#setFullBiasNanos(long):
+    Symmetric method for `hasFullBiasNanos` must be named `setHasFullBiasNanos`; was `setFullBiasNanos`
+GetterSetterNames: android.location.GnssClock#setLeapSecond(int):
+    Symmetric method for `hasLeapSecond` must be named `setHasLeapSecond`; was `setLeapSecond`
+GetterSetterNames: android.location.GnssClock#setReferenceCarrierFrequencyHzForIsb(double):
+    Symmetric method for `hasReferenceCarrierFrequencyHzForIsb` must be named `setHasReferenceCarrierFrequencyHzForIsb`; was `setReferenceCarrierFrequencyHzForIsb`
+GetterSetterNames: android.location.GnssClock#setReferenceCodeTypeForIsb(String):
+    Symmetric method for `hasReferenceCodeTypeForIsb` must be named `setHasReferenceCodeTypeForIsb`; was `setReferenceCodeTypeForIsb`
+GetterSetterNames: android.location.GnssClock#setReferenceConstellationTypeForIsb(int):
+    Symmetric method for `hasReferenceConstellationTypeForIsb` must be named `setHasReferenceConstellationTypeForIsb`; was `setReferenceConstellationTypeForIsb`
+GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
+    Symmetric method for `hasTimeUncertaintyNanos` must be named `setHasTimeUncertaintyNanos`; was `setTimeUncertaintyNanos`
+GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
+    Symmetric method for `hasBasebandCn0DbHz` must be named `setHasBasebandCn0DbHz`; was `setBasebandCn0DbHz`
+GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
+    Symmetric method for `hasCarrierFrequencyHz` must be named `setHasCarrierFrequencyHz`; was `setCarrierFrequencyHz`
+GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
+    Symmetric method for `hasCodeType` must be named `setHasCodeType`; was `setCodeType`
+GetterSetterNames: android.location.GnssMeasurement#setCorrelationVectors(java.util.Collection<android.location.CorrelationVector>):
+    Symmetric method for `hasCorrelationVectors` must be named `setHasCorrelationVectors`; was `setCorrelationVectors`
+GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasNanos(double):
+    Symmetric method for `hasFullInterSignalBiasNanos` must be named `setHasFullInterSignalBiasNanos`; was `setFullInterSignalBiasNanos`
+GetterSetterNames: android.location.GnssMeasurement#setFullInterSignalBiasUncertaintyNanos(double):
+    Symmetric method for `hasFullInterSignalBiasUncertaintyNanos` must be named `setHasFullInterSignalBiasUncertaintyNanos`; was `setFullInterSignalBiasUncertaintyNanos`
+GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasNanos(double):
+    Symmetric method for `hasSatelliteInterSignalBiasNanos` must be named `setHasSatelliteInterSignalBiasNanos`; was `setSatelliteInterSignalBiasNanos`
+GetterSetterNames: android.location.GnssMeasurement#setSatelliteInterSignalBiasUncertaintyNanos(double):
+    Symmetric method for `hasSatelliteInterSignalBiasUncertaintyNanos` must be named `setHasSatelliteInterSignalBiasUncertaintyNanos`; was `setSatelliteInterSignalBiasUncertaintyNanos`
+GetterSetterNames: android.location.GnssMeasurement#setSatellitePvt(android.location.SatellitePvt):
+    Symmetric method for `hasSatellitePvt` must be named `setHasSatellitePvt`; was `setSatellitePvt`
+GetterSetterNames: android.location.GnssMeasurement#setSnrInDb(double):
+    Symmetric method for `hasSnrInDb` must be named `setHasSnrInDb`; was `setSnrInDb`
+
+MissingNullability: android.location.GnssClock#set(android.location.GnssClock) parameter #0:
+    Missing nullability on parameter `clock` in method `set`
+MissingNullability: android.location.GnssMeasurement#set(android.location.GnssMeasurement) parameter #0:
+    Missing nullability on parameter `measurement` in method `set`
+MissingNullability: android.location.GnssNavigationMessage#set(android.location.GnssNavigationMessage) parameter #0:
+    Missing nullability on parameter `navigationMessage` in method `set`
+MissingNullability: android.location.GnssNavigationMessage#setData(byte[]) parameter #0:
+    Missing nullability on parameter `value` in method `setData`
diff --git a/location/java/Android.bp b/location/java/Android.bp
deleted file mode 100644
index 543f2b1..0000000
--- a/location/java/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
-    name: "framework-location-sources",
-    srcs: [
-        "**/*.java",
-        "**/*.aidl",
-    ],
-    visibility: ["//frameworks/base"],
-}
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index b0769ab..e28ad67 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -1525,50 +1525,61 @@
     /**
      * Gets the GNSS measurement's code type.
      *
-     * <p>Similar to the Attribute field described in RINEX 3.03, e.g., in Tables 4-10, and Table
-     * A2 at the RINEX 3.03 Update 1 Document.
+     * <p>Similar to the Attribute field described in RINEX 4.00, e.g., in Tables 9-16 (see
+     * https://igs.org/wg/rinex/#documents-formats).
      *
-     * <p>Returns "A" for GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA.
+     * <p>Returns "A" for GALILEO E1A, GALILEO E6A, IRNSS L5A SPS, IRNSS SA SPS, GLONASS G1a L1OCd,
+     * GLONASS G2a L2CSI.
      *
-     * <p>Returns "B" for GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB.
+     * <p>Returns "B" for GALILEO E1B, GALILEO E6B, IRNSS L5B RS (D), IRNSS SB RS (D), GLONASS G1a
+     * L1OCp, GLONASS G2a L2OCp, QZSS L1Sb.
      *
-     * <p>Returns "C" for GPS L1 C/A,  GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C,
-     * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+     * <p>Returns "C" for GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C,
+     * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C RS (P), IRNSS SC RS (P).
      *
-     * <p>Returns "D" for BDS B1C D.
+     * <p>Returns "D" for GPS L2 (L1(C/A) + (P2-P1) (semi-codeless)), QZSS L5S(I), BDS B1C Data,
+     * BDS B2a Data, BDS B2b Data, BDS B2 (B2a+B2b) Data, BDS B3a Data.
+     *
+     * <p>Returns “E” for QZSS L1 C/B, QZSS L6E.
      *
      * <p>Returns "I" for GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I, GALILEO E5a+b I,
      * SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
      *
-     * <p>Returns "L" for GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L), LEX(6) L.
+     * <p>Returns "L" for GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L), QZSS L6P, BDS
+     * B1a Pilot.
      *
      * <p>Returns "M" for GPS L1M, GPS L2M.
      *
      * <p>Returns "N" for GPS L1 codeless, GPS L2 codeless.
      *
-     * <p>Returns "P" for GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C P.
+     * <p>Returns "P" for GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C Pilot, BDS B2a Pilot,
+     * BDS B2b Pilot, BDS B2 (B2a+B2b) Pilot, BDS B3a Pilot, QZSS L5S(Q).
      *
      * <p>Returns "Q" for GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q,
      * SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
      *
-     * <p>Returns "S" for GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M), LEX(6) S.
+     * <p>Returns "S" for GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M), QZSS L6D, BDS B1a
+     * Data.
      *
      * <p>Returns "W" for GPS L1 Z-tracking, GPS L2 Z-tracking.
      *
-     * <p>Returns "X" for GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G3 (I+Q), GALILEO
-     * E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q), GALILEO E6 (B+C), SBAS
-     * L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), LEX(6) (S+L), BDS B1 (I+Q), BDS
-     * B1C (D+P), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+     * <p>Returns "X" for GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G1a L1OCd+L1OCp,
+     * GLONASS G2a L2CSI+L2OCp, GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO
+     * E5b (I+Q), GALILEO E5a+b (I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C
+     * (M+L), QZSS L5 (I+Q), QZSS L6 (D+P), BDS B1 (I+Q), BDS B1C Data+Pilot, BDS B2a Data+Pilot,
+     * BDS B2 (I+Q), BDS B2 (B2a+B2b) Data+Pilot, BDS B3 (I+Q), IRNSS L5 (B+C), IRNSS S (B+C).
      *
      * <p>Returns "Y" for GPS L1Y, GPS L2Y.
      *
-     * <p>Returns "Z" for GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF.
+     * <p>Returns "Z" for GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1S/L1-SAIF, QZSS L5S (I+Q),
+     * QZSS L6(D+E), BDS B1A Data+Pilot, BDS B2b Data+Pilot, BDS B3a Data+Pilot.
      *
      * <p>Returns "UNKNOWN" if the GNSS Measurement's code type is unknown.
      *
-     * <p>This is used to specify the observation descriptor defined in GNSS Observation Data File
-     * Header Section Description in the RINEX standard (Version 3.XX), in cases where the code type
-     * does not align with the above listed values. For example, if a code type "G" is added, this
+     * <p>The code type is used to specify the observation descriptor defined in GNSS Observation
+     * Data File Header Section Description in the RINEX standard (Version 4.00). In cases where
+     * the code type does not align with the above listed values, the code type from the most
+     * recent version of RINEX should be used. For example, if a code type "G" is added, this
      * string shall be set to "G".
      */
     @NonNull
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e2f4072..842542f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4945,7 +4945,9 @@
             synchronized (this) {
                 while (!mQuit) {
                     final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
-                    if (timeToWait < 0) { break; }
+                    if (timeToWait <= 0) {
+                        break;
+                    }
                     this.wait(timeToWait);
                 }
             }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 3f013de..61b5fd5 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -29,6 +29,7 @@
 import android.media.audio.common.AidlConversion;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
 import android.media.audiopolicy.AudioProductStrategy;
 import android.os.Build;
 import android.os.IBinder;
@@ -1955,6 +1956,11 @@
     /** @hide */
     public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
 
+    /** @hide */
+    public static native int updatePolicyMixes(
+            AudioMix[] mixes,
+            AudioMixingRule[] updatedMixingRules);
+
     /** @hide see AudioPolicy.setUidDeviceAffinities() */
     public static native int setUidDeviceAffinities(int uid, @NonNull int[] types,
             @NonNull String[] addresses);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e45ef40..0e7718b 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -54,6 +54,8 @@
 import android.media.PlayerBase;
 import android.media.VolumeInfo;
 import android.media.VolumePolicy;
+import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.AudioProductStrategy;
 import android.media.audiopolicy.AudioVolumeGroup;
@@ -356,6 +358,11 @@
 
     int removeMixForPolicy(in AudioPolicyConfig policyConfig, in IAudioPolicyCallback pcb);
 
+    @EnforcePermission("MODIFY_AUDIO_ROUTING")
+    int updateMixingRulesForPolicy(in AudioMix[] mixesToUpdate,
+                                   in AudioMixingRule[] updatedMixingRules,
+                                   in IAudioPolicyCallback pcb);
+
     int setFocusPropertiesForPolicy(int duckingBehavior, in IAudioPolicyCallback pcb);
 
     void setVolumePolicy(in VolumePolicy policy);
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index ea26185..1de0881 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -1155,7 +1155,7 @@
     public static final int OPTION_CLOSEST          = 0x03;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "OPTION_" }, value = {
+    @IntDef(flag = false, prefix = { "OPTION_" }, value = {
             OPTION_PREVIOUS_SYNC,
             OPTION_NEXT_SYNC,
             OPTION_CLOSEST_SYNC,
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index c4f2159..12db8c0 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -30,6 +30,7 @@
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.AssetFileDescriptor;
@@ -120,6 +121,53 @@
     public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER";
 
     /**
+     * Given to the ringtone picker as a string that represents the category of ringtone picker that
+     * should be used. This value should also be returned once a ringtone is selected.
+     * <p>
+     * The categories are:
+     * <li>{@link #CATEGORY_RINGTONE_PICKER_SOUND}
+     * <li>{@link #CATEGORY_RINGTONE_PICKER_VIBRATION}
+     * <li>{@link #CATEGORY_RINGTONE_PICKER_RINGTONE}
+     * <li>{@link Intent#CATEGORY_DEFAULT}
+     *
+     * <p> If the category is {@link Intent#CATEGORY_DEFAULT} or absent, then the picker will
+     * default to a sound-only ringtone picker.
+     *
+     * <p> If the selected category was not supported, then the returned category will be null.
+     *
+     * @hide
+     */
+    public static final String EXTRA_RINGTONE_PICKER_CATEGORY =
+            "android.intent.extra.ringtone.RINGTONE_PICKER_CATEGORY";
+
+    /**
+     * A sound-only ringtone picker.
+     *
+     * @hide
+     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
+     */
+    public static final String CATEGORY_RINGTONE_PICKER_SOUND =
+            "android.net.category.RINGTONE_PICKER_SOUND";
+
+    /**
+     * A vibration-only ringtone picker.
+     *
+     * @hide
+     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
+     */
+    public static final String CATEGORY_RINGTONE_PICKER_VIBRATION =
+            "android.net.category.RINGTONE_PICKER_VIBRATION";
+
+    /**
+     * A combined sound and vibration ringtone picker.
+     *
+     * @hide
+     * @see #EXTRA_RINGTONE_PICKER_CATEGORY
+     */
+    public static final String CATEGORY_RINGTONE_PICKER_RINGTONE =
+            "android.net.category.RINGTONE_PICKER_RINGTONE";
+
+    /**
      * Given to the ringtone picker as a boolean. Whether to show an item for
      * "Default".
      * 
@@ -160,6 +208,18 @@
      */
     public static final String EXTRA_RINGTONE_EXISTING_URI =
             "android.intent.extra.ringtone.EXISTING_URI";
+
+    /**
+     * Similar to #EXTRA_RINGTONE_EXISTING_URI but the {@link Uri} can include both sound and
+     * vibration.
+     * <p>This can include silent sound/vibration explicitly by setting that part of the URI to
+     * null.
+     *
+     * @hide
+     * @see #ACTION_RINGTONE_PICKER
+     */
+    public static final String EXTRA_RINGTONE_EXISTING_RINGTONE_URI =
+            "android.intent.extra.ringtone.RINGTONE_EXISTING_RINGTONE_URI";
     
     /**
      * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
diff --git a/media/java/android/media/audiopolicy/AudioMix.aidl b/media/java/android/media/audiopolicy/AudioMix.aidl
new file mode 100644
index 0000000..d17a644
--- /dev/null
+++ b/media/java/android/media/audiopolicy/AudioMix.aidl
@@ -0,0 +1,3 @@
+package android.media.audiopolicy;
+
+parcelable AudioMix;
\ No newline at end of file
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index d0270d3..48b4766 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -21,12 +21,15 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioSystem;
 import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -38,12 +41,12 @@
  * @hide
  */
 @SystemApi
-public class AudioMix {
+public class AudioMix implements Parcelable {
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private AudioMixingRule mRule;
+    private @NonNull AudioMixingRule mRule;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private AudioFormat mFormat;
+    private @NonNull AudioFormat mFormat;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private int mRouteFlags;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -54,7 +57,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     int mCallbackFlags;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    String mDeviceAddress;
+    @NonNull String mDeviceAddress;
 
     // initialized in constructor, read by AudioPolicyConfig
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -63,10 +66,11 @@
     /**
      * All parameters are guaranteed valid through the Builder.
      */
-    private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags,
-            int deviceType, String deviceAddress) {
-        mRule = rule;
-        mFormat = format;
+    private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format,
+            int routeFlags, int callbackFlags,
+            int deviceType, @Nullable String deviceAddress) {
+        mRule = Objects.requireNonNull(rule);
+        mFormat = Objects.requireNonNull(format);
         mRouteFlags = routeFlags;
         mMixType = rule.getTargetMixType();
         mCallbackFlags = callbackFlags;
@@ -187,6 +191,15 @@
     }
 
     /** @hide */
+    public void setAudioMixingRule(@NonNull AudioMixingRule rule) {
+        if (mRule.getTargetMixType() != rule.getTargetMixType()) {
+            throw new UnsupportedOperationException(
+                    "Target mix role of updated rule doesn't match the mix role of the AudioMix");
+        }
+        mRule = Objects.requireNonNull(rule);
+    }
+
+    /** @hide */
     public String getRegistration() {
         return mDeviceAddress;
     }
@@ -269,6 +282,49 @@
         return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
     }
 
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // write mix route flags
+        dest.writeInt(mRouteFlags);
+        // write callback flags
+        dest.writeInt(mCallbackFlags);
+        // write device information
+        dest.writeInt(mDeviceSystemType);
+        dest.writeString8(mDeviceAddress);
+        mFormat.writeToParcel(dest, flags);
+        mRule.writeToParcel(dest, flags);
+    }
+
+    public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
+        /**
+         * Rebuilds an AudioMix previously stored with writeToParcel().
+         *
+         * @param p Parcel object to read the AudioMix from
+         * @return a new AudioMix created from the data in the parcel
+         */
+        public AudioMix createFromParcel(Parcel p) {
+            final AudioMix.Builder mixBuilder = new AudioMix.Builder();
+            // read mix route flags
+            mixBuilder.setRouteFlags(p.readInt());
+            // read callback flags
+            mixBuilder.setCallbackFlags(p.readInt());
+            // read device information
+            mixBuilder.setDevice(p.readInt(), p.readString8());
+            mixBuilder.setFormat(AudioFormat.CREATOR.createFromParcel(p));
+            mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
+            return mixBuilder.build();
+        }
+
+        public AudioMix[] newArray(int size) {
+            return new AudioMix[size];
+        }
+    };
+
     /** @hide */
     @IntDef(flag = true,
             value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
@@ -298,7 +354,7 @@
          * @param rule a non-null {@link AudioMixingRule} instance.
          * @throws IllegalArgumentException
          */
-        public Builder(AudioMixingRule rule)
+        public Builder(@NonNull AudioMixingRule rule)
                 throws IllegalArgumentException {
             if (rule == null) {
                 throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -313,7 +369,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        Builder setMixingRule(AudioMixingRule rule)
+        Builder setMixingRule(@NonNull AudioMixingRule rule)
                 throws IllegalArgumentException {
             if (rule == null) {
                 throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -358,7 +414,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        public Builder setFormat(AudioFormat format)
+        public Builder setFormat(@NonNull AudioFormat format)
                 throws IllegalArgumentException {
             if (format == null) {
                 throw new IllegalArgumentException("Illegal null AudioFormat argument");
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.aidl b/media/java/android/media/audiopolicy/AudioMixingRule.aidl
new file mode 100644
index 0000000..5c06538
--- /dev/null
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.aidl
@@ -0,0 +1,3 @@
+package android.media.audiopolicy;
+
+parcelable AudioMixingRule;
\ No newline at end of file
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 9c0b825f..e5debb8 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -26,8 +26,11 @@
 import android.media.MediaRecorder;
 import android.os.Build;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -50,7 +53,7 @@
  * </pre>
  */
 @SystemApi
-public class AudioMixingRule {
+public class AudioMixingRule implements Parcelable {
 
     private AudioMixingRule(int mixType, Collection<AudioMixMatchCriterion> criteria,
                             boolean allowPrivilegedMediaPlaybackCapture,
@@ -130,7 +133,7 @@
             RULE_EXCLUSION_MASK | RULE_MATCH_AUDIO_SESSION_ID;
 
     /** @hide */
-    public static final class AudioMixMatchCriterion {
+    public static final class AudioMixMatchCriterion implements Parcelable {
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         final AudioAttributes mAttr;
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -139,18 +142,44 @@
         final int mRule;
 
         /** input parameters must be valid */
-        AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
+        @VisibleForTesting
+        public AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
             mAttr = attributes;
             mIntProp = Integer.MIN_VALUE;
             mRule = rule;
         }
         /** input parameters must be valid */
-        AudioMixMatchCriterion(Integer intProp, int rule) {
+        @VisibleForTesting
+        public AudioMixMatchCriterion(Integer intProp, int rule) {
             mAttr = null;
             mIntProp = intProp.intValue();
             mRule = rule;
         }
 
+        private AudioMixMatchCriterion(@NonNull Parcel in) {
+            Objects.requireNonNull(in);
+            mRule = in.readInt();
+            final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
+            switch (match_rule) {
+                case RULE_MATCH_ATTRIBUTE_USAGE:
+                case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+                    mAttr = AudioAttributes.CREATOR.createFromParcel(in);
+                    mIntProp = Integer.MIN_VALUE;
+                    break;
+                case RULE_MATCH_UID:
+                case RULE_MATCH_USERID:
+                case RULE_MATCH_AUDIO_SESSION_ID:
+                    mIntProp = in.readInt();
+                    mAttr = null;
+                    break;
+                default:
+                    // assume there was in int value to read as for now they come in pair
+                    in.readInt();
+                    throw new IllegalArgumentException(
+                            "Illegal rule value " + mRule + " in parcel");
+            }
+        }
+
         @Override
         public int hashCode() {
             return Objects.hash(mAttr, mIntProp, mRule);
@@ -170,7 +199,13 @@
                     && Objects.equals(mAttr, other.mAttr);
         }
 
-        void writeToParcel(Parcel dest) {
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeInt(mRule);
             final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
             switch (match_rule) {
@@ -190,6 +225,22 @@
             }
         }
 
+        public static final @NonNull Parcelable.Creator<AudioMixMatchCriterion> CREATOR =
+                new Parcelable.Creator<>() {
+            /**
+             * Rebuilds an AudioMixMatchCriterion previously stored with writeToParcel().
+             *
+             * @param p Parcel object to read the AudioMix from
+             * @return a new AudioMixMatchCriterion created from the data in the parcel
+             */
+            public AudioMixMatchCriterion createFromParcel(Parcel p) {
+                return new AudioMixMatchCriterion(p);
+            }
+            public AudioMixMatchCriterion[] newArray(int size) {
+                return new AudioMixMatchCriterion[size];
+            }
+        };
+
         public AudioAttributes getAudioAttributes() { return mAttr; }
         public int getIntProp() { return mIntProp; }
         public int getRule() { return mRule; }
@@ -605,13 +656,14 @@
                 if (!(property instanceof AudioAttributes)) {
                     throw new IllegalArgumentException("Invalid AudioAttributes argument");
                 }
-                return addRuleInternal((AudioAttributes) property, null, rule);
+                return addRuleInternal(
+                        new AudioMixMatchCriterion((AudioAttributes) property, rule));
             } else {
                 // implies integer match rule
                 if (!(property instanceof Integer)) {
                     throw new IllegalArgumentException("Invalid Integer argument");
                 }
-                return addRuleInternal(null, (Integer) property, rule);
+                return addRuleInternal(new AudioMixMatchCriterion((Integer) property, rule));
             }
         }
 
@@ -636,12 +688,13 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        private Builder addRuleInternal(AudioAttributes attrToMatch, Integer intProp, int rule)
+        private Builder addRuleInternal(AudioMixMatchCriterion criterion)
                 throws IllegalArgumentException {
             // If mix type is invalid and added rule is valid only for the players / recorders,
             // adjust the mix type accordingly.
             // Otherwise, if the mix type was already deduced or set explicitly, verify the rule
             // is valid for the mix type.
+            final int rule = criterion.mRule;
             if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
                 if (isPlayerRule(rule)) {
                     mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
@@ -655,51 +708,16 @@
             }
             synchronized (mCriteria) {
                 int oppositeRule = rule ^ RULE_EXCLUSION_MASK;
-                if (mCriteria.stream().anyMatch(criterion -> criterion.mRule == oppositeRule)) {
+                if (mCriteria.stream().anyMatch(
+                        otherCriterion -> otherCriterion.mRule == oppositeRule)) {
                     throw new IllegalArgumentException("AudioMixingRule cannot contain RULE_MATCH_*"
                             + " and RULE_EXCLUDE_* for the same dimension.");
                 }
-                int ruleWithoutExclusion = rule & ~RULE_EXCLUSION_MASK;
-                switch (ruleWithoutExclusion) {
-                    case RULE_MATCH_ATTRIBUTE_USAGE:
-                    case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
-                        mCriteria.add(new AudioMixMatchCriterion(attrToMatch, rule));
-                        break;
-                    case RULE_MATCH_UID:
-                    case RULE_MATCH_USERID:
-                    case RULE_MATCH_AUDIO_SESSION_ID:
-                        mCriteria.add(new AudioMixMatchCriterion(intProp, rule));
-                        break;
-                    default:
-                        throw new IllegalStateException("Unreachable code in addRuleInternal()");
-                }
+                mCriteria.add(criterion);
             }
             return this;
         }
 
-        Builder addRuleFromParcel(Parcel in) throws IllegalArgumentException {
-            final int rule = in.readInt();
-            final int match_rule = rule & ~RULE_EXCLUSION_MASK;
-            AudioAttributes attr = null;
-            Integer intProp = null;
-            switch (match_rule) {
-                case RULE_MATCH_ATTRIBUTE_USAGE:
-                case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
-                    attr =  AudioAttributes.CREATOR.createFromParcel(in);
-                    break;
-                case RULE_MATCH_UID:
-                case RULE_MATCH_USERID:
-                case RULE_MATCH_AUDIO_SESSION_ID:
-                    intProp = new Integer(in.readInt());
-                    break;
-                default:
-                    // assume there was in int value to read as for now they come in pair
-                    in.readInt();
-                    throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
-            }
-            return addRuleInternal(attr, intProp, rule);
-        }
-
         /**
          * Combines all of the matching and exclusion rules that have been set and return a new
          * {@link AudioMixingRule} object.
@@ -717,4 +735,52 @@
                     mVoiceCommunicationCaptureAllowed);
         }
     }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // write opt-out respect
+        dest.writeBoolean(mAllowPrivilegedPlaybackCapture);
+        // write voice communication capture allowed flag
+        dest.writeBoolean(mVoiceCommunicationCaptureAllowed);
+        // write specified mix type
+        dest.writeInt(mTargetMixType);
+        // write mix rules
+        dest.writeInt(mCriteria.size());
+        for (AudioMixingRule.AudioMixMatchCriterion criterion : mCriteria) {
+            criterion.writeToParcel(dest, flags);
+        }
+    }
+
+    public static final @NonNull Parcelable.Creator<AudioMixingRule> CREATOR =
+            new Parcelable.Creator<>() {
+
+        @Override
+        public AudioMixingRule createFromParcel(Parcel source) {
+            AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
+            // read opt-out respect
+            ruleBuilder.allowPrivilegedPlaybackCapture(source.readBoolean());
+            // read voice capture allowed flag
+            ruleBuilder.voiceCommunicationCaptureAllowed(source.readBoolean());
+            // read specified mix type
+            ruleBuilder.setTargetMixRole(source.readInt());
+            // read mix rules
+            int nbRules = source.readInt();
+            for (int j = 0; j < nbRules; j++) {
+                // read the matching rules
+                ruleBuilder.addRuleInternal(
+                        AudioMixMatchCriterion.CREATOR.createFromParcel(source));
+            }
+            return ruleBuilder.build();
+        }
+
+        @Override
+        public AudioMixingRule[] newArray(int size) {
+            return new AudioMixingRule[size];
+        }
+    };
 }
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 3e5de82..e9a6ed4 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -44,6 +44,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -408,6 +409,39 @@
     }
 
     /**
+     * Update {@link AudioMixingRule}-s of already registered {@link AudioMix}-es.
+     *
+     * @param mixingRuleUpdates - {@link List} of {@link Pair}-s, each pair containing
+     *  {@link AudioMix} to update and its new corresponding {@link AudioMixingRule}.
+     *
+     * @return {@link AudioManager#SUCCESS} if the update was successful,
+     *  {@link AudioManager#ERROR} otherwise.
+     */
+    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public int updateMixingRules(
+            @NonNull List<Pair<AudioMix, AudioMixingRule>> mixingRuleUpdates) {
+        Objects.requireNonNull(mixingRuleUpdates);
+
+        IAudioService service = getService();
+        try {
+            synchronized (mLock) {
+                final int status = service.updateMixingRulesForPolicy(
+                        mixingRuleUpdates.stream().map(p -> p.first).toArray(AudioMix[]::new),
+                        mixingRuleUpdates.stream().map(p -> p.second).toArray(
+                                AudioMixingRule[]::new),
+                        cb());
+                if (status == AudioManager.SUCCESS) {
+                    mConfig.updateMixingRules(mixingRuleUpdates);
+                }
+                return status;
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Received remote exeception in updateMixingRules call: ", e);
+            return AudioManager.ERROR;
+        }
+    }
+
+    /**
      * @hide
      * Configures the audio framework so that all audio streams originating from the given UID
      * can only come from a set of audio devices.
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 7a85d21..d277c7d 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -17,16 +17,17 @@
 package android.media.audiopolicy;
 
 import android.annotation.NonNull;
-import android.media.AudioFormat;
 import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -85,72 +86,20 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mMixes.size());
         for (AudioMix mix : mMixes) {
-            // write mix route flags
-            dest.writeInt(mix.getRouteFlags());
-            // write callback flags
-            dest.writeInt(mix.mCallbackFlags);
-            // write device information
-            dest.writeInt(mix.mDeviceSystemType);
-            dest.writeString(mix.mDeviceAddress);
-            // write mix format
-            dest.writeInt(mix.getFormat().getSampleRate());
-            dest.writeInt(mix.getFormat().getEncoding());
-            dest.writeInt(mix.getFormat().getChannelMask());
-            // write opt-out respect
-            dest.writeBoolean(mix.getRule().allowPrivilegedMediaPlaybackCapture());
-            // write voice communication capture allowed flag
-            dest.writeBoolean(mix.getRule().voiceCommunicationCaptureAllowed());
-            // write specified mix type
-            dest.writeInt(mix.getRule().getTargetMixRole());
-            // write mix rules
-            final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
-            dest.writeInt(criteria.size());
-            for (AudioMixMatchCriterion criterion : criteria) {
-                criterion.writeToParcel(dest);
-            }
+            mix.writeToParcel(dest, flags);
         }
     }
 
     private AudioPolicyConfig(Parcel in) {
-        mMixes = new ArrayList<AudioMix>();
         int nbMixes = in.readInt();
+        mMixes = new ArrayList<>(nbMixes);
         for (int i = 0 ; i < nbMixes ; i++) {
-            final AudioMix.Builder mixBuilder = new AudioMix.Builder();
-            // read mix route flags
-            int routeFlags = in.readInt();
-            mixBuilder.setRouteFlags(routeFlags);
-            // read callback flags
-            mixBuilder.setCallbackFlags(in.readInt());
-            // read device information
-            mixBuilder.setDevice(in.readInt(), in.readString());
-            // read mix format
-            int sampleRate = in.readInt();
-            int encoding = in.readInt();
-            int channelMask = in.readInt();
-            final AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate)
-                    .setChannelMask(channelMask).setEncoding(encoding).build();
-            mixBuilder.setFormat(format);
-
-            AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
-            // read opt-out respect
-            ruleBuilder.allowPrivilegedPlaybackCapture(in.readBoolean());
-            // read voice capture allowed flag
-            ruleBuilder.voiceCommunicationCaptureAllowed(in.readBoolean());
-            // read specified mix type
-            ruleBuilder.setTargetMixRole(in.readInt());
-            // read mix rules
-            int nbRules = in.readInt();
-            for (int j = 0 ; j < nbRules ; j++) {
-                // read the matching rules
-                ruleBuilder.addRuleFromParcel(in);
-            }
-            mixBuilder.setMixingRule(ruleBuilder.build());
-            mMixes.add(mixBuilder.build());
+            mMixes.add(AudioMix.CREATOR.createFromParcel(in));
         }
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<AudioPolicyConfig> CREATOR
-            = new Parcelable.Creator<AudioPolicyConfig>() {
+    public static final @android.annotation.NonNull Parcelable.Creator<AudioPolicyConfig> CREATOR =
+            new Parcelable.Creator<>() {
         /**
          * Rebuilds an AudioPolicyConfig previously stored with writeToParcel().
          * @param p Parcel object to read the AudioPolicyConfig from
@@ -309,6 +258,23 @@
         }
     }
 
+    /**
+     * Update audio mixing rules for already registered {@link AudioMix}-es.
+     *
+     * @param audioMixingRuleUpdates {@link List} of {@link Pair}-s containing {@link AudioMix} to
+     *                                           be updated and the new {@link AudioMixingRule}.
+     */
+    public void updateMixingRules(
+            @NonNull List<Pair<AudioMix, AudioMixingRule>> audioMixingRuleUpdates) {
+        Objects.requireNonNull(audioMixingRuleUpdates).forEach(
+                update -> updateMixingRule(update.first, update.second));
+    }
+
+    private void updateMixingRule(AudioMix audioMixToUpdate, AudioMixingRule audioMixingRule) {
+        mMixes.stream().filter(audioMixToUpdate::equals).findAny().ifPresent(
+                mix -> mix.setAudioMixingRule(audioMixingRule));
+    }
+
     private static String mixTypeId(int type) {
         if (type == AudioMix.MIX_TYPE_PLAYERS) return "p";
         else if (type == AudioMix.MIX_TYPE_RECORDERS) return "r";
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index da2e56f..382e65d 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -617,7 +617,7 @@
                         "match the ImageReader's configured buffer format 0x%x.",
                         bufferFormat, ctx->getBufferFormat());
                 jniThrowException(env, "java/lang/UnsupportedOperationException",
-                        msg.string());
+                        msg.c_str());
                 return -1;
             }
         }
@@ -795,7 +795,7 @@
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
                 " must be 0", halReaderFormat, numPlanes);
-        jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg.c_str());
         return NULL;
     }
 
@@ -860,7 +860,7 @@
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
                 " must be 0", halReaderFormat, numPlanes);
-        jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg.c_str());
         return NULL;
     }
 
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 1927b6c..f64233f 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -1068,7 +1068,7 @@
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
                 " must be 0", writerFormat, numPlanes);
-        jniThrowException(env, "java/lang/IllegalArgumentException", msg.string());
+        jniThrowException(env, "java/lang/IllegalArgumentException", msg.c_str());
         return NULL;
     }
 
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index f491be8..5506f61 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -299,7 +299,7 @@
             std::string strerr(StrCryptoError(err));
             msg.appendFormat(": general failure (%s)", strerr.c_str());
         }
-        jniThrowException(env, "android/media/MediaCryptoException", msg.string());
+        jniThrowException(env, "android/media/MediaCryptoException", msg.c_str());
     }
 }
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index b70818d..c616b84f 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -708,8 +708,8 @@
     jclass clazz = gFields.hashmapClassId;
     jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
     for (size_t i = 0; i < map.size(); ++i) {
-        jstring jkey = env->NewStringUTF(map.keyAt(i).string());
-        jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
+        jstring jkey = env->NewStringUTF(map.keyAt(i).c_str());
+        jstring jvalue = env->NewStringUTF(map.valueAt(i).c_str());
         env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
         env->DeleteLocalRef(jkey);
         env->DeleteLocalRef(jvalue);
@@ -1169,7 +1169,7 @@
         jbyteArray jrequest = VectorToJByteArray(env, request);
         env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest);
 
-        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
         env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl);
 
         switch (keyRequestType) {
@@ -1332,7 +1332,7 @@
         jbyteArray jrequest = VectorToJByteArray(env, request);
         env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
 
-        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+        jstring jdefaultUrl = env->NewStringUTF(defaultUrl.c_str());
         env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
     }
 
@@ -1686,7 +1686,7 @@
         return NULL;
     }
 
-    return env->NewStringUTF(value.string());
+    return env->NewStringUTF(value.c_str());
 }
 
 static jbyteArray android_media_MediaDrm_getPropertyByteArray(
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index ddc51cd..1458758 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -126,7 +126,7 @@
     tmp = NULL;
 
     // Don't let somebody trick us in to reading some random block of memory
-    if (strncmp("mem://", pathStr.string(), 6) == 0) {
+    if (strncmp("mem://", pathStr.c_str(), 6) == 0) {
         jniThrowException(
                 env, "java/lang/IllegalArgumentException", "Invalid pathname");
         return;
@@ -149,7 +149,7 @@
             env,
             retriever->setDataSource(
                 httpService,
-                pathStr.string(),
+                pathStr.c_str(),
                 headersVector.size() > 0 ? &headersVector : NULL),
 
             "java/lang/RuntimeException",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 44aff64..3551ea4 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1234,7 +1234,7 @@
     String8 vendorMessage;
     if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
         vendorMessage = String8::format("DRM vendor-defined error: %d", err);
-        drmMessage = vendorMessage.string();
+        drmMessage = vendorMessage.c_str();
     }
 
     if (err == BAD_VALUE) {
@@ -1260,7 +1260,7 @@
                 msg = drmMessage;
             } else {
                 errbuf = String8::format("%s: %s", msg, drmMessage);
-                msg = errbuf.string();
+                msg = errbuf.c_str();
             }
         }
         throwDrmStateException(env, msg, err);
diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp
index 4fd5153..dffeb89 100644
--- a/media/jni/android_media_Streams.cpp
+++ b/media/jni/android_media_Streams.cpp
@@ -38,7 +38,7 @@
 
 FileStream::FileStream(const String8 filename)
     : mPosition(0) {
-    mFile = fopen(filename.string(), "r");
+    mFile = fopen(filename.c_str(), "r");
     if (mFile == NULL) {
         return;
     }
@@ -86,7 +86,7 @@
 
     if (!piex::IsRaw(stream)) {
         // Format not supported.
-        ALOGV("Format not supported: %s", filename.string());
+        ALOGV("Format not supported: %s", filename.c_str());
         return false;
     }
 
@@ -94,7 +94,7 @@
 
     if (err != piex::Error::kOk) {
         // The input data seems to be broken.
-        ALOGV("Raw image not detected: %s (piex error code: %d)", filename.string(), (int32_t)err);
+        ALOGV("Raw image not detected: %s (piex error code: %d)", filename.c_str(), (int32_t)err);
         return false;
     }
 
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
deleted file mode 100644
index a26398a..0000000
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
+++ /dev/null
@@ -1,274 +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.audiopolicytest;
-
-import static android.media.AudioFormat.CHANNEL_OUT_MONO;
-import static android.media.AudioFormat.CHANNEL_OUT_STEREO;
-import static android.media.AudioFormat.ENCODING_PCM_16BIT;
-import static android.media.audiopolicy.AudioMixingRule.MIX_ROLE_INJECTOR;
-import static android.media.audiopolicy.AudioMixingRule.MIX_ROLE_PLAYERS;
-import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_AUDIO_SESSION_ID;
-import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_UID;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-
-import android.media.AudioFormat;
-import android.media.AudioSystem;
-import android.media.audiopolicy.AudioMix;
-import android.media.audiopolicy.AudioMixingRule;
-import android.media.audiopolicy.AudioPolicyConfig;
-import android.os.Parcel;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.google.common.testing.EqualsTester;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Unit tests for AudioMix.
- *
- * Run with "atest AudioMixUnitTests".
- */
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class AudioMixUnitTests {
-    private static final AudioFormat OUTPUT_FORMAT_STEREO_44KHZ_PCM =
-            new AudioFormat.Builder()
-                    .setSampleRate(44000)
-                    .setChannelMask(CHANNEL_OUT_STEREO)
-                    .setEncoding(ENCODING_PCM_16BIT).build();
-    private static final AudioFormat OUTPUT_FORMAT_MONO_16KHZ_PCM =
-            new AudioFormat.Builder()
-                    .setSampleRate(16000)
-                    .setChannelMask(CHANNEL_OUT_MONO)
-                    .setEncoding(ENCODING_PCM_16BIT).build();
-    private static final AudioFormat INPUT_FORMAT_MONO_16KHZ_PCM =
-            new AudioFormat.Builder()
-                    .setSampleRate(16000)
-                    .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
-                    .setEncoding(ENCODING_PCM_16BIT).build();
-
-    @Test
-    public void testEquals() {
-        final EqualsTester equalsTester = new EqualsTester();
-
-        // --- Equality group 1
-        final AudioMix playbackAudioMixWithSessionId42AndUid123 =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, 42)
-                        .addMixRule(RULE_MATCH_UID, 123).build())
-                        .setFormat(OUTPUT_FORMAT_STEREO_44KHZ_PCM)
-                        .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-        final AudioMix playbackAudioMixWithUid123AndSessionId42 =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_UID, 123)
-                        .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, 42).build())
-                        .setFormat(OUTPUT_FORMAT_STEREO_44KHZ_PCM)
-                        .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-        equalsTester.addEqualityGroup(
-                playbackAudioMixWithSessionId42AndUid123,
-                playbackAudioMixWithUid123AndSessionId42,
-                writeToAndFromParcel(playbackAudioMixWithSessionId42AndUid123),
-                writeToAndFromParcel(playbackAudioMixWithUid123AndSessionId42));
-
-        // --- Equality group 2
-        final AudioMix recordingAudioMixWithSessionId42AndUid123 =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_INJECTOR)
-                        .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, 42)
-                        .addMixRule(RULE_MATCH_UID, 123).build())
-                        .setFormat(INPUT_FORMAT_MONO_16KHZ_PCM)
-                        .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-        final AudioMix recordingAudioMixWithUid123AndSessionId42 =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_INJECTOR)
-                        .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, 42)
-                        .addMixRule(RULE_MATCH_UID, 123).build())
-                        .setFormat(INPUT_FORMAT_MONO_16KHZ_PCM)
-                        .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-        equalsTester.addEqualityGroup(recordingAudioMixWithSessionId42AndUid123,
-                recordingAudioMixWithUid123AndSessionId42,
-                writeToAndFromParcel(recordingAudioMixWithSessionId42AndUid123),
-                writeToAndFromParcel(recordingAudioMixWithUid123AndSessionId42));
-
-        // --- Equality group 3
-        final AudioMix recordingAudioMixWithSessionId42AndUid123Render =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, 42)
-                        .addMixRule(RULE_MATCH_UID, 123).build())
-                        .setFormat(INPUT_FORMAT_MONO_16KHZ_PCM)
-                        .setRouteFlags(
-                                AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER).build();
-        equalsTester.addEqualityGroup(recordingAudioMixWithSessionId42AndUid123Render,
-                writeToAndFromParcel(recordingAudioMixWithSessionId42AndUid123Render));
-
-        // --- Equality group 4
-        final AudioMix playbackAudioMixWithUid123 =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_UID, 123).build())
-                        .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                        .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-        equalsTester.addEqualityGroup(playbackAudioMixWithUid123,
-                writeToAndFromParcel(playbackAudioMixWithUid123));
-
-        // --- Equality group 5
-        final AudioMix playbackAudioMixWithUid42 =
-                new AudioMix.Builder(new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_UID, 42).build())
-                        .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                        .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-        equalsTester.addEqualityGroup(playbackAudioMixWithUid42,
-                writeToAndFromParcel(playbackAudioMixWithUid42));
-
-        equalsTester.testEquals();
-    }
-
-    @Test
-    public void buildRenderToRemoteSubmix_success() {
-        final String deviceAddress = "address";
-        final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
-                .setTargetMixRole(MIX_ROLE_PLAYERS)
-                .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
-                .setDevice(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, /*address=*/deviceAddress).build();
-
-        assertEquals(deviceAddress, audioMix.getRegistration());
-        assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
-        assertEquals(AudioMix.ROUTE_FLAG_RENDER, audioMix.getRouteFlags());
-    }
-
-    @Test
-    public void buildLoopbackAndRenderToRemoteSubmix_success() {
-        final String deviceAddress = "address";
-        final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
-                .setTargetMixRole(MIX_ROLE_PLAYERS)
-                .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK_RENDER)
-                .setDevice(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, /*address=*/deviceAddress).build();
-
-        assertEquals(deviceAddress, audioMix.getRegistration());
-        assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
-        assertEquals(AudioMix.ROUTE_FLAG_LOOP_BACK_RENDER, audioMix.getRouteFlags());
-    }
-
-    @Test
-    public void buildRenderToSpeaker_success() {
-        final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
-                .setTargetMixRole(MIX_ROLE_PLAYERS)
-                .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
-                .setDevice(AudioSystem.DEVICE_OUT_SPEAKER, /*address=*/"").build();
-
-        assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
-        assertEquals(AudioMix.ROUTE_FLAG_RENDER, audioMix.getRouteFlags());
-    }
-
-    @Test
-    public void buildLoopbackForPlayerMix_success() {
-        final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
-                .setTargetMixRole(MIX_ROLE_PLAYERS)
-                .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-
-        assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
-        assertEquals(AudioMix.ROUTE_FLAG_LOOP_BACK, audioMix.getRouteFlags());
-    }
-
-    @Test
-    public void buildLoopbackForInjectorMix_success() {
-        final AudioMix audioMix = new AudioMix.Builder(new AudioMixingRule.Builder()
-                .setTargetMixRole(MIX_ROLE_INJECTOR)
-                .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK).build();
-
-        assertEquals(OUTPUT_FORMAT_MONO_16KHZ_PCM, audioMix.getFormat());
-        assertEquals(AudioMix.ROUTE_FLAG_LOOP_BACK, audioMix.getRouteFlags());
-    }
-
-    @Test
-    public void buildLoopbackWithIncompatibleDevice_throws() {
-        assertThrows(IllegalArgumentException.class, () -> new AudioMix.Builder(
-                new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK)
-                .setDevice(AudioSystem.DEVICE_OUT_SPEAKER, /*address=*/"").build());
-    }
-
-    @Test
-    public void buildRenderWithoutDevice_throws() {
-        assertThrows(IllegalArgumentException.class, () -> new AudioMix.Builder(
-                new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER).build());
-    }
-
-    @Test
-    public void buildRenderWithInputDevice_throws() {
-        assertThrows(IllegalArgumentException.class, () -> new AudioMix.Builder(
-                new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
-                .setDevice(AudioSystem.DEVICE_IN_BUILTIN_MIC, /*address=*/"").build());
-    }
-
-    @Test
-    public void buildRenderWithInjectorMix_throws() {
-        assertThrows(IllegalArgumentException.class, () -> new AudioMix.Builder(
-                new AudioMixingRule.Builder()
-                        .setTargetMixRole(MIX_ROLE_INJECTOR)
-                        .addMixRule(RULE_MATCH_UID, 42).build())
-                .setFormat(OUTPUT_FORMAT_MONO_16KHZ_PCM)
-                .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
-                .setDevice(AudioSystem.DEVICE_OUT_SPEAKER, /*address=*/"").build());
-    }
-
-
-
-    private static AudioMix writeToAndFromParcel(AudioMix audioMix) {
-        AudioPolicyConfig apc = new AudioPolicyConfig(new ArrayList<>(List.of(audioMix)));
-        Parcel parcel = Parcel.obtain();
-        apc.writeToParcel(parcel, /*flags=*/0);
-        parcel.setDataPosition(0);
-        AudioMix unmarshalledMix =
-                AudioPolicyConfig.CREATOR.createFromParcel(parcel).getMixes().get(0);
-        parcel.recycle();
-        return unmarshalledMix;
-    }
-}
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java
deleted file mode 100644
index 3cbfd50..0000000
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java
+++ /dev/null
@@ -1,322 +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.audiopolicytest;
-
-import static android.media.AudioAttributes.USAGE_MEDIA;
-import static android.media.MediaRecorder.AudioSource.VOICE_RECOGNITION;
-import static android.media.audiopolicy.AudioMixingRule.MIX_ROLE_INJECTOR;
-import static android.media.audiopolicy.AudioMixingRule.MIX_ROLE_PLAYERS;
-import static android.media.audiopolicy.AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET;
-import static android.media.audiopolicy.AudioMixingRule.RULE_EXCLUDE_ATTRIBUTE_USAGE;
-import static android.media.audiopolicy.AudioMixingRule.RULE_EXCLUDE_AUDIO_SESSION_ID;
-import static android.media.audiopolicy.AudioMixingRule.RULE_EXCLUDE_UID;
-import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
-import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE;
-import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_AUDIO_SESSION_ID;
-import static android.media.audiopolicy.AudioMixingRule.RULE_MATCH_UID;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
-import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-
-
-import android.media.AudioAttributes;
-import android.media.audiopolicy.AudioMixingRule;
-import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.hamcrest.CustomTypeSafeMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Unit tests for AudioPolicy.
- *
- * Run with "atest AudioMixingRuleUnitTests".
- */
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class AudioMixingRuleUnitTests {
-    private static final AudioAttributes USAGE_MEDIA_AUDIO_ATTRIBUTES =
-            new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build();
-    private static final AudioAttributes CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES =
-            new AudioAttributes.Builder().setCapturePreset(VOICE_RECOGNITION).build();
-    private static final int TEST_UID = 42;
-    private static final int OTHER_UID = 77;
-    private static final int TEST_SESSION_ID = 1234;
-
-    @Test
-    public void testConstructValidRule() {
-        AudioMixingRule rule = new AudioMixingRule.Builder()
-                .addMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                .addMixRule(RULE_MATCH_UID, TEST_UID)
-                .excludeMixRule(RULE_MATCH_AUDIO_SESSION_ID, TEST_SESSION_ID)
-                .build();
-
-        // Based on the rules, the mix type should fall back to MIX_ROLE_PLAYERS,
-        // since the rules are valid for both MIX_ROLE_PLAYERS & MIX_ROLE_INJECTOR.
-        assertEquals(rule.getTargetMixRole(), MIX_ROLE_PLAYERS);
-        assertThat(rule.getCriteria(), containsInAnyOrder(
-                isAudioMixMatchUsageCriterion(USAGE_MEDIA),
-                isAudioMixMatchUidCriterion(TEST_UID),
-                isAudioMixExcludeSessionCriterion(TEST_SESSION_ID)));
-    }
-
-    @Test
-    public void testConstructRuleWithConflictingCriteriaFails() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        .addMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                        .addMixRule(RULE_MATCH_UID, TEST_UID)
-                        // Conflicts with previous criterion.
-                        .addMixRule(RULE_EXCLUDE_UID, OTHER_UID)
-                        .build());
-    }
-
-    @Test
-    public void testRuleBuilderDedupsCriteria() {
-        AudioMixingRule rule = new AudioMixingRule.Builder()
-                .addMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                .addMixRule(RULE_MATCH_UID, TEST_UID)
-                // Identical to previous criterion.
-                .addMixRule(RULE_MATCH_UID, TEST_UID)
-                // Identical to first criterion.
-                .addMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                .build();
-
-        assertThat(rule.getCriteria(), hasSize(2));
-        assertThat(rule.getCriteria(), containsInAnyOrder(
-                isAudioMixMatchUsageCriterion(USAGE_MEDIA),
-                isAudioMixMatchUidCriterion(TEST_UID)));
-    }
-
-    @Test
-    public void failsWhenAddAttributeRuleCalledWithInvalidType() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        // Rule match attribute usage requires AudioAttributes, not
-                        // just the int enum value of the usage.
-                        .addMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA)
-                        .build());
-    }
-
-    @Test
-    public void failsWhenExcludeAttributeRuleCalledWithInvalidType() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        // Rule match attribute usage requires AudioAttributes, not
-                        // just the int enum value of the usage.
-                        .excludeMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA)
-                        .build());
-    }
-
-    @Test
-    public void failsWhenAddIntRuleCalledWithInvalidType() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        // Rule match uid requires Integer not AudioAttributes.
-                        .addMixRule(RULE_MATCH_UID, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                        .build());
-    }
-
-    @Test
-    public void failsWhenExcludeIntRuleCalledWithInvalidType() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        // Rule match uid requires Integer not AudioAttributes.
-                        .excludeMixRule(RULE_MATCH_UID, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                        .build());
-    }
-
-    @Test
-    public void injectorMixTypeDeductionWithGenericRuleSucceeds() {
-        AudioMixingRule rule = new AudioMixingRule.Builder()
-                // UID rule can be used both with MIX_ROLE_PLAYERS and MIX_ROLE_INJECTOR.
-                .addMixRule(RULE_MATCH_UID, TEST_UID)
-                // Capture preset rule is only valid for injector, MIX_ROLE_INJECTOR should
-                // be deduced.
-                .addMixRule(RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
-                        CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES)
-                .build();
-
-        assertEquals(rule.getTargetMixRole(), MIX_ROLE_INJECTOR);
-        assertThat(rule.getCriteria(), containsInAnyOrder(
-                isAudioMixMatchUidCriterion(TEST_UID),
-                isAudioMixMatchCapturePresetCriterion(VOICE_RECOGNITION)));
-    }
-
-    @Test
-    public void settingTheMixTypeToIncompatibleInjectorMixFails() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        .addMixRule(RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
-                                CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES)
-                        // Capture preset cannot be defined for MIX_ROLE_PLAYERS.
-                        .setTargetMixRole(MIX_ROLE_PLAYERS)
-                        .build());
-    }
-
-    @Test
-    public void addingPlayersOnlyRuleWithInjectorsOnlyRuleFails() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder()
-                        // MIX_ROLE_PLAYERS only rule.
-                        .addMixRule(RULE_MATCH_ATTRIBUTE_USAGE, USAGE_MEDIA_AUDIO_ATTRIBUTES)
-                        // MIX ROLE_INJECTOR only rule.
-                        .addMixRule(RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
-                                CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES)
-                        .build());
-    }
-
-    @Test
-    public void sessionIdRuleCompatibleWithPlayersMix() {
-        int sessionId = 42;
-        AudioMixingRule rule = new AudioMixingRule.Builder()
-                .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, sessionId)
-                .setTargetMixRole(MIX_ROLE_PLAYERS)
-                .build();
-
-        assertEquals(rule.getTargetMixRole(), MIX_ROLE_PLAYERS);
-        assertThat(rule.getCriteria(), containsInAnyOrder(isAudioMixSessionCriterion(sessionId)));
-    }
-
-    @Test
-    public void sessionIdRuleCompatibleWithInjectorMix() {
-        AudioMixingRule rule = new AudioMixingRule.Builder()
-                .addMixRule(RULE_MATCH_AUDIO_SESSION_ID, TEST_SESSION_ID)
-                .setTargetMixRole(MIX_ROLE_INJECTOR)
-                .build();
-
-        assertEquals(rule.getTargetMixRole(), MIX_ROLE_INJECTOR);
-        assertThat(rule.getCriteria(),
-                containsInAnyOrder(isAudioMixSessionCriterion(TEST_SESSION_ID)));
-    }
-
-    @Test
-    public void audioMixingRuleWithNoRulesFails() {
-        assertThrows(IllegalArgumentException.class,
-                () -> new AudioMixingRule.Builder().build());
-    }
-
-
-    private static Matcher isAudioMixUidCriterion(int uid, boolean exclude) {
-        return new CustomTypeSafeMatcher<AudioMixMatchCriterion>("uid mix criterion") {
-            @Override
-            public boolean matchesSafely(AudioMixMatchCriterion item) {
-                int expectedRule = exclude ? RULE_EXCLUDE_UID : RULE_MATCH_UID;
-                return item.getRule() == expectedRule && item.getIntProp() == uid;
-            }
-
-            @Override
-            public void describeMismatchSafely(
-                    AudioMixMatchCriterion item, Description mismatchDescription) {
-                mismatchDescription.appendText(
-                        String.format("is not %s criterion with uid %d",
-                                exclude ? "exclude" : "match", uid));
-            }
-        };
-    }
-
-    private static Matcher isAudioMixMatchUidCriterion(int uid) {
-        return isAudioMixUidCriterion(uid, /*exclude=*/ false);
-    }
-
-    private static Matcher isAudioMixCapturePresetCriterion(int audioSource, boolean exclude) {
-        return new CustomTypeSafeMatcher<AudioMixMatchCriterion>("uid mix criterion") {
-            @Override
-            public boolean matchesSafely(AudioMixMatchCriterion item) {
-                int expectedRule = exclude
-                        ? RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET
-                        : RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
-                AudioAttributes attributes = item.getAudioAttributes();
-                return item.getRule() == expectedRule
-                        && attributes != null && attributes.getCapturePreset() == audioSource;
-            }
-
-            @Override
-            public void describeMismatchSafely(
-                    AudioMixMatchCriterion item, Description mismatchDescription) {
-                mismatchDescription.appendText(
-                        String.format("is not %s criterion with capture preset %d",
-                                exclude ? "exclude" : "match", audioSource));
-            }
-        };
-    }
-
-    private static Matcher isAudioMixMatchCapturePresetCriterion(int audioSource) {
-        return isAudioMixCapturePresetCriterion(audioSource, /*exclude=*/ false);
-    }
-
-    private static Matcher isAudioMixUsageCriterion(int usage, boolean exclude) {
-        return new CustomTypeSafeMatcher<AudioMixMatchCriterion>("usage mix criterion") {
-            @Override
-            public boolean matchesSafely(AudioMixMatchCriterion item) {
-                int expectedRule =
-                        exclude ? RULE_EXCLUDE_ATTRIBUTE_USAGE : RULE_MATCH_ATTRIBUTE_USAGE;
-                AudioAttributes attributes = item.getAudioAttributes();
-                return item.getRule() == expectedRule
-                        && attributes != null && attributes.getUsage() == usage;
-            }
-
-            @Override
-            public void describeMismatchSafely(
-                    AudioMixMatchCriterion item, Description mismatchDescription) {
-                mismatchDescription.appendText(
-                        String.format("is not %s criterion with usage %d",
-                                exclude ? "exclude" : "match", usage));
-            }
-        };
-    }
-
-    private static Matcher isAudioMixMatchUsageCriterion(int usage) {
-        return isAudioMixUsageCriterion(usage, /*exclude=*/ false);
-    }
-
-    private static Matcher isAudioMixSessionCriterion(int sessionId, boolean exclude) {
-        return new CustomTypeSafeMatcher<AudioMixMatchCriterion>("sessionId mix criterion") {
-            @Override
-            public boolean matchesSafely(AudioMixMatchCriterion item) {
-                int excludeRule =
-                        exclude ? RULE_EXCLUDE_AUDIO_SESSION_ID : RULE_MATCH_AUDIO_SESSION_ID;
-                return item.getRule() == excludeRule && item.getIntProp() == sessionId;
-            }
-
-            @Override
-            public void describeMismatchSafely(
-                    AudioMixMatchCriterion item, Description mismatchDescription) {
-                mismatchDescription.appendText(
-                        String.format("is not %s criterion with session id %d",
-                        exclude ? "exclude" : "match", sessionId));
-            }
-        };
-    }
-
-    private static Matcher isAudioMixSessionCriterion(int sessionId) {
-        return isAudioMixSessionCriterion(sessionId, /*exclude=*/ false);
-    }
-
-    private static Matcher isAudioMixExcludeSessionCriterion(int sessionId) {
-        return isAudioMixSessionCriterion(sessionId, /*exclude=*/ true);
-    }
-
-}
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index 69cf804..1878716 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -118,7 +118,7 @@
     // the string to return and advance the iterator for next time.
     if (index < max) {
         assetDir->mCachedFileName = assetDir->mAssetDir->getFileName(index);
-        returnName = assetDir->mCachedFileName.string();
+        returnName = assetDir->mCachedFileName.c_str();
         index++;
     }
 
@@ -134,7 +134,7 @@
 const char* AAssetDir_getFileName(AAssetDir* assetDir, int index)
 {
     assetDir->mCachedFileName = assetDir->mAssetDir->getFileName(index);
-    return assetDir->mCachedFileName.string();
+    return assetDir->mCachedFileName.c_str();
 }
 
 void AAssetDir_close(AAssetDir* assetDir)
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 968de34..bb8708b 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -304,12 +304,12 @@
 
 const char* ASensor_getName(ASensor const* sensor) {
     RETURN_IF_SENSOR_IS_NULL(nullptr);
-    return static_cast<Sensor const*>(sensor)->getName().string();
+    return static_cast<Sensor const*>(sensor)->getName().c_str();
 }
 
 const char* ASensor_getVendor(ASensor const* sensor) {
     RETURN_IF_SENSOR_IS_NULL(nullptr);
-    return static_cast<Sensor const*>(sensor)->getVendor().string();
+    return static_cast<Sensor const*>(sensor)->getVendor().c_str();
 }
 
 int ASensor_getType(ASensor const* sensor) {
@@ -339,7 +339,7 @@
 
 const char* ASensor_getStringType(ASensor const* sensor) {
     RETURN_IF_SENSOR_IS_NULL(nullptr);
-    return static_cast<Sensor const*>(sensor)->getStringType().string();
+    return static_cast<Sensor const*>(sensor)->getStringType().c_str();
 }
 
 int ASensor_getReportingMode(ASensor const* sensor) {
diff --git a/native/android/storage_manager.cpp b/native/android/storage_manager.cpp
index 294ca9c..6db87df 100644
--- a/native/android/storage_manager.cpp
+++ b/native/android/storage_manager.cpp
@@ -175,7 +175,7 @@
         String16 filename16(filename);
         String16 path16;
         if (mMountService->getMountedObbPath(filename16, path16)) {
-            return String8(path16).string();
+            return String8(path16).c_str();
         } else {
             return NULL;
         }
@@ -183,7 +183,7 @@
 };
 
 void ObbActionListener::onObbResult(const android::String16& filename, const int32_t nonce, const int32_t state) {
-    mStorageManager->fireCallback(String8(filename).string(), nonce, state);
+    mStorageManager->fireCallback(String8(filename).c_str(), nonce, state);
 }
 
 
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index cb01f2d..5d491db 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -26,7 +26,7 @@
     <string name="profile_name_glasses" msgid="3506504967216601277">"อุปกรณ์"</string>
     <string name="summary_glasses" msgid="2872254734959842579">"แอปนี้จะได้รับสิทธิ์ดังต่อไปนี้ใน<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ของคุณ"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
-    <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
+    <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการข้ามอุปกรณ์"</string>
     <string name="helper_summary_app_streaming" msgid="2396773196949578425">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> เพื่อสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 4d97803..8d06765 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -53,7 +53,7 @@
     <string name="save_password_on_other_device_title" msgid="5829084591948321207">"Θέλετε να αποθηκεύσετε τον κωδικό πρόσβασης σε κάποια άλλη συσκευή;"</string>
     <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Θέλετε να αποθηκεύσετε τα στοιχεία σύνδεσης σε κάποια άλλη συσκευή;"</string>
     <string name="use_provider_for_all_title" msgid="4201020195058980757">"Να χρησιμοποιηθεί το <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> για όλες τις συνδέσεις σας;"</string>
-    <string name="use_provider_for_all_description" msgid="1998772715863958997">"Αυτός ο διαχειριστής κωδικών πρόσβασης για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g> θα αποθηκεύει τους κωδικούς πρόσβασης και τα κλειδιά πρόσβασης, για πιο εύκολη πρόσβαση"</string>
+    <string name="use_provider_for_all_description" msgid="1998772715863958997">"Αυτός ο διαχειριστής κωδικών πρόσβασης για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g> θα αποθηκεύει τους κωδικούς και τα κλειδιά πρόσβασης, για πιο εύκολη σύνδεση"</string>
     <string name="set_as_default" msgid="4415328591568654603">"Ορισμός ως προεπιλογής"</string>
     <string name="settings" msgid="6536394145760913145">"Ρυθμίσεις"</string>
     <string name="use_once" msgid="9027366575315399714">"Χρήση μία φορά"</string>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index 88afea4..a6e0d3d 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -56,7 +56,7 @@
     <string name="use_provider_for_all_description" msgid="1998772715863958997">"این مدیر گذرواژه برای <xliff:g id="USERNAME">%1$s</xliff:g> گذرکلیدها و گذرواژه‌های شما را ذخیره می‌کند تا به‌راحتی بتوانید به سیستم وارد شوید"</string>
     <string name="set_as_default" msgid="4415328591568654603">"تنظیم به‌عنوان پیش‌فرض"</string>
     <string name="settings" msgid="6536394145760913145">"تنظیمات"</string>
-    <string name="use_once" msgid="9027366575315399714">"یک‌بار استفاده"</string>
+    <string name="use_once" msgid="9027366575315399714">"این بار استفاده شود"</string>
     <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> گذرکلید"</string>
     <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه"</string>
     <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> گذرکلید"</string>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index d986a93..05d21e0 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -56,7 +56,7 @@
     <string name="use_provider_for_all_description" msgid="1998772715863958997">"<xliff:g id="USERNAME">%1$s</xliff:g> के लिए यह पासवर्ड मैनेजर, आपके पासवर्ड और पासकी सेव करेगा, ताकि आपको साइन इन करने में आसानी हो"</string>
     <string name="set_as_default" msgid="4415328591568654603">"डिफ़ॉल्ट के तौर पर सेट करें"</string>
     <string name="settings" msgid="6536394145760913145">"सेटिंग"</string>
-    <string name="use_once" msgid="9027366575315399714">"इसका इस्तेमाल एक बार किया जा सकता है"</string>
+    <string name="use_once" msgid="9027366575315399714">"एक बार इस्तेमाल करें"</string>
     <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
     <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड"</string>
     <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> पासकी"</string>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index b597a9a..ed42f3a 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -52,7 +52,7 @@
     <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"გსურთ სხვა მოწყობილობაზე წვდომის გასაღებების შექმნა?"</string>
     <string name="save_password_on_other_device_title" msgid="5829084591948321207">"გსურთ სხვა მოწყობილობაზე პაროლის შენახვა?"</string>
     <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"გსურთ სხვა მოწყობილობაზე ავტორიზაციის მონაცემების შენახვა?"</string>
-    <string name="use_provider_for_all_title" msgid="4201020195058980757">"გსურთ, გამოიყენოთ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> სისტემაში ყველა შესვლისთვის?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"გსურთ, გამოიყენოთ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> სისტემაში ყველა შესვლისთვის?"</string>
     <string name="use_provider_for_all_description" msgid="1998772715863958997">"მოცემული პაროლების მმართველი <xliff:g id="USERNAME">%1$s</xliff:g>-ისთვის შეინახავს თქვენს პაროლებს და წვდომის გასაღებს, რომლებიც დაგეხმარებათ სისტემაში მარტივად შესვლაში"</string>
     <string name="set_as_default" msgid="4415328591568654603">"ნაგულისხმევად დაყენება"</string>
     <string name="settings" msgid="6536394145760913145">"პარამეტრები"</string>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index ae680a0..7447ab6 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -52,7 +52,7 @@
     <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"ಇನ್ನೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್‌ಕೀ ಅನ್ನು ರಚಿಸಬೇಕೆ?"</string>
     <string name="save_password_on_other_device_title" msgid="5829084591948321207">"ಇನ್ನೊಂದು ಸಾಧನದಲ್ಲಿ ಪಾಸ್‌ವರ್ಡ್ ಉಳಿಸಬೇಕೆ?"</string>
     <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"ಮತ್ತೊಂದು ಸಾಧನದಲ್ಲಿ ಸೈನ್-ಇನ್ ಅನ್ನು ಉಳಿಸಬೇಕೆ?"</string>
-    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ನಿಮ್ಮ ಎಲ್ಲಾ ಸೈನ್-ಇನ್‌ಗಳಿಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸುವುದೇ?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ನಿಮ್ಮ ಎಲ್ಲಾ ಸೈನ್-ಇನ್‌ಗಳಿಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸಬೇಕೇ?"</string>
     <string name="use_provider_for_all_description" msgid="1998772715863958997">"<xliff:g id="USERNAME">%1$s</xliff:g> ಗಾಗಿ ಈ ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕವು ನಿಮಗೆ ಸುಲಭವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುವುದಕ್ಕೆ ಸಹಾಯ ಮಾಡಲು ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಾಸ್‌ಕೀಗಳನ್ನು ಸಂಗ್ರಹಿಸುತ್ತದೆ"</string>
     <string name="set_as_default" msgid="4415328591568654603">"ಡೀಫಾಲ್ಟ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ"</string>
     <string name="settings" msgid="6536394145760913145">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index d5f5f7f..c3b941b 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -52,7 +52,7 @@
     <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Sukurti „passkey“ kitame įrenginyje?"</string>
     <string name="save_password_on_other_device_title" msgid="5829084591948321207">"Išsaugoti slaptažodį kitame įrenginyje?"</string>
     <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Išsaugoti prisijungimo duomenis kitame įrenginyje?"</string>
-    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Naudoti <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> visada prisijungiant?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Naudoti „<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>“ visada prisijungiant?"</string>
     <string name="use_provider_for_all_description" msgid="1998772715863958997">"Šioje <xliff:g id="USERNAME">%1$s</xliff:g> Slaptažodžių tvarkyklėje bus saugomi jūsų slaptažodžiai ir prieigos raktai, kad galėtumėte lengvai prisijungti"</string>
     <string name="set_as_default" msgid="4415328591568654603">"Nustatyti kaip numatytąjį"</string>
     <string name="settings" msgid="6536394145760913145">"Nustatymai"</string>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index 0755c9c..1f456bf 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -56,7 +56,7 @@
     <string name="use_provider_for_all_description" msgid="1998772715863958997">"Овој управник со лозинки за <xliff:g id="USERNAME">%1$s</xliff:g> ќе ги складира вашите лозинки и криптографски клучеви за да ви помогне лесно да се најавите"</string>
     <string name="set_as_default" msgid="4415328591568654603">"Постави како стандардна опција"</string>
     <string name="settings" msgid="6536394145760913145">"Поставки"</string>
-    <string name="use_once" msgid="9027366575315399714">"Употребете еднаш"</string>
+    <string name="use_once" msgid="9027366575315399714">"Употреби го еднаш"</string>
     <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Лозинки: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> • Криптографски клучеви: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
     <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> лозинки"</string>
     <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Криптографски клучеви: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index 8168b51..90805a4 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -53,7 +53,7 @@
     <string name="save_password_on_other_device_title" msgid="5829084591948321207">"Chcete uložiť heslo v inom zariadení?"</string>
     <string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Chcete uložiť prihlasovacie údaje v inom zariadení?"</string>
     <string name="use_provider_for_all_title" msgid="4201020195058980757">"Chcete pre všetky svoje prihlasovacie údaje použiť <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
-    <string name="use_provider_for_all_description" msgid="1998772715863958997">"Tento správca hesiel poskytovateľa <xliff:g id="USERNAME">%1$s</xliff:g> uchová vaše heslá a prístupové kľúče, aby vám pomohol ľahšie sa prihlasovať"</string>
+    <string name="use_provider_for_all_description" msgid="1998772715863958997">"Tento správca hesiel pre účet <xliff:g id="USERNAME">%1$s</xliff:g> bude uchovávať vaše heslá a prístupové kľúče, aby ste sa mohli ľahšie prihlasovať"</string>
     <string name="set_as_default" msgid="4415328591568654603">"Nastaviť ako predvolené"</string>
     <string name="settings" msgid="6536394145760913145">"Nastavenia"</string>
     <string name="use_once" msgid="9027366575315399714">"Použiť raz"</string>
diff --git a/packages/EncryptedLocalTransport/Android.bp b/packages/EncryptedLocalTransport/Android.bp
index 09e5630..9ae6d96 100644
--- a/packages/EncryptedLocalTransport/Android.bp
+++ b/packages/EncryptedLocalTransport/Android.bp
@@ -27,9 +27,6 @@
     name: "EncryptedLocalTransport",
     defaults: ["platform_app_defaults"],
     srcs: ["src/**/*.java"],
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
     static_libs: ["LocalTransport"],
     platform_apis: true,
     certificate: "platform",
diff --git a/packages/EncryptedLocalTransport/proguard.flags b/packages/EncryptedLocalTransport/proguard.flags
deleted file mode 100644
index e4ce3c5..0000000
--- a/packages/EncryptedLocalTransport/proguard.flags
+++ /dev/null
@@ -1,2 +0,0 @@
--keep class com.android.localTransport.EncryptedLocalTransport
--keep class com.android.localTransport.EncryptedLocalTransportService
diff --git a/packages/Keyguard/proguard.flags b/packages/Keyguard/proguard.flags
deleted file mode 100644
index fb74b64..0000000
--- a/packages/Keyguard/proguard.flags
+++ /dev/null
@@ -1,27 +0,0 @@
--keep public class * {
-  public void setBackgroundAlpha(float);
-  public float getBackgroundAlpha();
-  public void setContentAlpha(float);
-  public float getContentAlpha();
-  public void setAlpha(float);
-  public float getAlpha();
-  public void setAlpha(int);
-  public int getAlpha();
-  public void setRotationX(float);
-  public float getRotationX();
-  public void setRotationY(float);
-  public float getRotationY();
-  public void setPivotX(float);
-  public float getPivotX();
-  public void setPivotY(float);
-  public float getPivotY();
-  public void setScaleX(float);
-  public float getScaleX();
-  public void setScaleY(float);
-  public float getScaleY();
-  public void setTranslationX(float);
-  public float getTranslationX();
-  public void setTranslationY(float);
-  public float getTranslationY();
-}
-
diff --git a/packages/LocalTransport/Android.bp b/packages/LocalTransport/Android.bp
index d4fa191..e7a273b 100644
--- a/packages/LocalTransport/Android.bp
+++ b/packages/LocalTransport/Android.bp
@@ -27,9 +27,7 @@
     name: "LocalTransport",
     defaults: ["platform_app_defaults"],
     srcs: ["src/**/*.java"],
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
+    libs: ["keepanno-annotations"],
     platform_apis: true,
     certificate: "platform",
     privileged: true,
diff --git a/packages/LocalTransport/proguard.flags b/packages/LocalTransport/proguard.flags
deleted file mode 100644
index c1f51b8..0000000
--- a/packages/LocalTransport/proguard.flags
+++ /dev/null
@@ -1,5 +0,0 @@
--keep class com.android.localTransport.LocalTransport
--keep class com.android.localTransport.LocalTransportParameters
--keep class com.android.localTransport.LocalTransportService
-
-
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 73f8730..933be11 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -38,6 +38,9 @@
 import android.util.Base64;
 import android.util.Log;
 
+import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.keepanno.annotations.UsesReflection;
+
 import libcore.io.IoUtils;
 
 import java.io.BufferedOutputStream;
@@ -127,6 +130,13 @@
         return mParameters;
     }
 
+
+    @UsesReflection({
+            // As the runtime class name is used to generate the returned name, and the returned
+            // name may be used used with reflection, generate the necessary keep rules.
+            @KeepTarget(classConstant = LocalTransport.class),
+            @KeepTarget(extendsClassConstant = LocalTransport.class)
+    })
     @Override
     public String name() {
         return new ComponentName(mContext, this.getClass()).flattenToShortString();
diff --git a/packages/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index 03e3925..9ee0882 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -50,7 +50,7 @@
     <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Impossibile installare <xliff:g id="APP_NAME">%1$s</xliff:g>. Libera dello spazio e riprova."</string>
     <string name="app_not_found_dlg_title" msgid="5107924008597470285">"App non trovata"</string>
     <string name="app_not_found_dlg_text" msgid="5219983779377811611">"Impossibile trovare l\'applicazione nell\'elenco di applicazioni installate."</string>
-    <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Non autorizzate"</string>
+    <string name="user_is_not_allowed_dlg_title" msgid="6915293433252210232">"Non autorizzata"</string>
     <string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"L\'utente corrente non è autorizzato a eseguire questa disinstallazione."</string>
     <string name="generic_error_dlg_title" msgid="5863195085927067752">"Errore"</string>
     <string name="generic_error_dlg_text" msgid="5287861443265795232">"Impossibile disinstallare l\'app."</string>
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 3d35bad..5dcb9d2 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -8,7 +8,6 @@
 }
 
 android_library {
-
     name: "SettingsLib",
 
     static_libs: [
@@ -26,44 +25,20 @@
         "iconloader",
 
         "WifiTrackerLibRes",
-        "SettingsLibHelpUtils",
-        "SettingsLibRestrictedLockUtils",
-        "SettingsLibActionBarShadow",
-        "SettingsLibAppPreference",
-        "SettingsLibSearchWidget",
-        "SettingsLibSettingsSpinner",
-        "SettingsLibIllustrationPreference",
-        "SettingsLibLayoutPreference",
-        "SettingsLibMainSwitchPreference",
-        "SettingsLibActionButtonsPreference",
-        "SettingsLibEntityHeaderWidgets",
-        "SettingsLibBarChartPreference",
-        "SettingsLibProgressBar",
-        "SettingsLibAdaptiveIcon",
-        "SettingsLibRadioButtonPreference",
-        "SettingsLibSelectorWithWidgetPreference",
-        "SettingsLibDisplayUtils",
-        "SettingsLibUtils",
-        "SettingsLibEmergencyNumber",
-        "SettingsLibTopIntroPreference",
-        "SettingsLibBannerMessagePreference",
-        "SettingsLibFooterPreference",
-        "SettingsLibUsageProgressBarPreference",
-        "SettingsLibCollapsingToolbarBaseActivity",
-        "SettingsLibTwoTargetPreference",
-        "SettingsLibSettingsTransition",
-        "SettingsLibButtonPreference",
         "SettingsLibDeviceStateRotationLock",
-        "SettingsLibProfileSelector",
+        "SettingsLibDisplayUtils",
+        "SettingsLibEmergencyNumber",
+        "SettingsLibSearchWidget",
+        "SettingsLibUtils",
+        "SettingsLibWidget",
         "setupdesign",
         "zxing-core-1.7",
         "androidx.room_room-runtime",
         "settingslib_flags_lib",
-
     ],
 
     plugins: ["androidx.room_room-compiler-plugin"],
-
+    use_resource_processor: true,
     resource_dirs: ["res"],
 
     srcs: [
@@ -72,6 +47,43 @@
     ],
 }
 
+// Group all the libraries with namespace "com.android.settingslib.widget", to allow SettingsLib to
+// set use_resource_processor = true.
+// We can remove SettingsLibWidget when all these libraries have its own namespace.
+android_library {
+    name: "SettingsLibWidget",
+    visibility: ["//visibility:private"],
+    manifest: "AndroidManifest-SettingsLibWidget.xml",
+    static_libs: [
+        "SettingsLibActionBarShadow",
+        "SettingsLibActionButtonsPreference",
+        "SettingsLibAdaptiveIcon",
+        "SettingsLibAppPreference",
+        "SettingsLibBannerMessagePreference",
+        "SettingsLibBarChartPreference",
+        "SettingsLibButtonPreference",
+        "SettingsLibCollapsingToolbarBaseActivity",
+        "SettingsLibEntityHeaderWidgets",
+        "SettingsLibFooterPreference",
+        "SettingsLibHelpUtils",
+        "SettingsLibIllustrationPreference",
+        "SettingsLibLayoutPreference",
+        "SettingsLibMainSwitchPreference",
+        "SettingsLibProfileSelector",
+        "SettingsLibProgressBar",
+        "SettingsLibRadioButtonPreference",
+        "SettingsLibRestrictedLockUtils",
+        "SettingsLibSelectorWithWidgetPreference",
+        "SettingsLibSettingsSpinner",
+        "SettingsLibSettingsTransition",
+        "SettingsLibTopIntroPreference",
+        "SettingsLibTwoTargetPreference",
+        "SettingsLibUsageProgressBarPreference",
+    ],
+
+    resource_dirs: [],
+}
+
 // NOTE: Keep this module in sync with ./common.mk
 java_defaults {
     name: "SettingsLibDefaults",
diff --git a/packages/SettingsLib/AndroidManifest-SettingsLibWidget.xml b/packages/SettingsLib/AndroidManifest-SettingsLibWidget.xml
new file mode 100644
index 0000000..38a7d6a
--- /dev/null
+++ b/packages/SettingsLib/AndroidManifest-SettingsLibWidget.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<manifest package="com.android.settingslib.widget" />
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 90a723f..b77368a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -253,6 +253,7 @@
             hideTitleSemantics = false,
             navigationIcon = navigationIcon,
             actions = actionsRow,
+            titleScaleDisabled = false,
         )
     }
 }
@@ -426,6 +427,7 @@
  * accessibility services at the same time, when animating between collapsed / expanded states.
  * @param navigationIcon a navigation icon [Composable]
  * @param actions actions [Composable]
+ * @param titleScaleDisabled whether the title font scaling is disabled. Default is disabled.
  */
 @Composable
 private fun TopAppBarLayout(
@@ -443,6 +445,7 @@
     hideTitleSemantics: Boolean,
     navigationIcon: @Composable () -> Unit,
     actions: @Composable () -> Unit,
+    titleScaleDisabled: Boolean = true,
 ) {
     Layout(
         {
@@ -466,9 +469,12 @@
                 ProvideTextStyle(value = titleTextStyle) {
                     CompositionLocalProvider(
                         LocalContentColor provides titleContentColor,
-                        // Disable the title font scaling by only passing the density but not the
-                        // font scale.
-                        LocalDensity provides Density(density = LocalDensity.current.density),
+                        LocalDensity provides with(LocalDensity.current) {
+                          Density(
+                              density = density,
+                              fontScale = if (titleScaleDisabled) 1f else fontScale,
+                          )
+                        },
                         content = title
                     )
                 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index d437e35..696e877 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -18,6 +18,7 @@
 
 import androidx.activity.compose.BackHandler
 import androidx.appcompat.R
+import androidx.compose.foundation.focusable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.RowScope
@@ -96,7 +97,8 @@
             Modifier
                 .padding(paddingValues.horizontalValues())
                 .padding(top = paddingValues.calculateTopPadding())
-                .fillMaxSize(),
+                .focusable()
+                .fillMaxSize()
         ) {
             content(
                 paddingValues.calculateBottomPadding(),
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 8e4c6a4..9b82c13 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Maak die groottes van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Aktiveer vormvrye vensters"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktiveer steun vir eksperimentele vormvrye vensters."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Rekenaarmodus"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Werkskerm-rugsteunwagwoord"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tik om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 6011eb16..bd025ec 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች መጠናቸው የሚቀየሩ እንዲሆኑ ያደርጋቸዋል።"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"የሙከራ ነፃ መልክ መስኮቶች ድጋፍን አንቃ"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"የዴስክቶፕ ሁነታ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"የዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃሉን ለመለወጥ ወይም ለማስወገድ ነካ ያድርጉ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 40c92e5..f5ab801 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"السماح بتغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"تفعيل النوافذ الحرة"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"إتاحة استخدام النوافذ الحرة التجريبية"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"وضع سطح المكتب"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"كلمة مرور احتياطية للكمبيوتر"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"النُسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"انقر لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها."</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index ef72afc..a0a52b5 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"মেনিফেষ্টৰ মান যিয়েই নহওক, মাল্টি-ৱিণ্ডৰ বাবে আটাইবোৰ কাৰ্যকলাপৰ আকাৰ সলনি কৰিব পৰা কৰক।"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ফ্ৰিফৰ্ম ৱিণ্ড\'জ সক্ষম কৰক"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"পৰীক্ষামূলক ফ্ৰী-ফৰ্ম ৱিণ্ড’বোৰৰ বাবে সহায়তা সক্ষম কৰক৷"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ডেস্কটপ ম’ড"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ডেস্কটপ বেকআপ পাছৱৰ্ড"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ডেস্কটপৰ পূৰ্ণ বেকআপ এতিয়ালৈকে সংৰক্ষিত অৱস্থাত নাই"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ডেস্কটপ সম্পূৰ্ণ বেকআপৰ বাবে পাছৱৰ্ডটো সলনি কৰিবলৈ বা আঁতৰাবলৈ টিপক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index a76f8ba..cb515bf 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest dəyərindən asılı olmayaraq çoxpəncərəli rejimdə pəncərə ölçüsünün dəyişdirilməsinə icazə verilsin"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"İxtiyari formada pəncərə yaradılsın"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Eksperimental olaraq ixtiyari formada pəncərə yaradılsın"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Masaüstü rejimi"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Masaüstü rezerv parolu"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Masaüstünün tam rezerv kopyalanması üçün parolu dəyişmək və ya silmək üçün basın"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 4d7a5fe..0119674 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore proizvoljnog formata"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućava podršku za eksperimentalne prozore proizvoljnog formata."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Režim za računare"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Lozinka rezervne kopije za računar"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f46adf8..b46debf 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Зрабіць усе віды дзейнасці даступнымі для змены памеру ў рэжыме некалькіх вокнаў, незалежна ад значэнняў маніфеста."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Уключыць адвольную форму вокнаў"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Уключыць падтрымку для эксперыментальнай адвольнай формы акна."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Рэжым працоўнага стала"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Пароль для рэз. копіі ПК"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Поўнае рэзервовае капіраванне працоўнага стала зараз не абаронена"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Краніце, каб змяніць або выдаліць пароль для поўнага рэзервовага капіравання працоўнага стала"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index fa3cba2..592f617 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Активиране на прозорците в свободна форма"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Активиране на поддръжката за експерименталните прозорци в свободна форма."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Режим за компютри"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Парола за резервни копия"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index d3dc359..3fafee3 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলির আকার পরিবর্তনযোগ্য করুন৷"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ফ্রি-ফর্ম উইন্ডো চালু করুন"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"পরীক্ষামূলক ফ্রি-ফর্ম উইন্ডোগুলির জন্য সহায়তা সক্ষম করুন৷"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"\'ডেস্কটপ\' মোড"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ডেস্কটপের সম্পূর্ণ ব্যাকআপের পাসওয়ার্ডটি পরিবর্তন করতে বা মুছে ফেলতে আলতো চাপুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 0487e29..5f7bd2c 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogućava mijenjanje veličine svih aktivnosti za prikaz s više prozora, bez obzira na prikazane vrijednosti"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore nepravilnih oblika"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućava podršku za eksperimentalne prozore nepravilnih oblika."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Način rada radne površine"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Lozinka sigurnosne kopije za računar"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije s radne površine"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 62938eb..7143f99 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors del manifest"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activa les finestres amb format lliure"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activa la compatibilitat amb finestres experimentals amb format lliure"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Mode d\'escriptori"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Contrasenya per a còpies d\'ordinador"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les còpies de seguretat completes d\'ordinador no estan protegides"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca per canviar o suprimir la contrasenya per a les còpies de seguretat completes de l\'ordinador"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index d6aa84e..34e65e63 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Umožní změnu velikosti všech aktivit na několik oken (bez ohledu na hodnoty manifestu)"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivovat okna s volným tvarem"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivuje podporu experimentálních oken s volným tvarem"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Režim počítače"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Heslo pro zálohy v počítači"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy do počítače"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index d1b0222..381c3cc6 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tillad, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivér vinduer i frit format"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivér understøttelse af eksperimentelle vinduer i frit format"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Computertilstand"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Kode til lokal backup"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Lokale komplette backups er i øjeblikket ikke beskyttet"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal backup"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a74374a..b53d191 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Die Größe aller Aktivitäten darf, ungeachtet der Manifestwerte, für die Mehrfensterdarstellung angepasst werden"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Freiform-Fenster zulassen"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Unterstützung für experimentelle Freiform-Fenster aktivieren"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktopmodus"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Passwort für Desktop-Sicherung"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 9f000bb..b4cc7aa 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ενεργοποίηση υποστήριξης για πειραματικά παράθυρα ελεύθερης μορφής."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Λειτ. επιφάνειας εργασίας"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Εφ/κός κωδικός desktop"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Πατήστε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 5bb58d1..9fd825b 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 5b1e86f..546e5d2 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren’t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 5bb58d1..9fd825b 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 5bb58d1..9fd825b 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Make all activities resizeable for multi-window, regardless of manifest values."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Enable freeform windows"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Enable support for experimental freeform windows."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tap to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 8f4ba0e..8256cc9 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‎Make all activities resizable for multi-window, regardless of manifest values.‎‏‎‎‏‎"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎Enable freeform windows‎‏‎‎‏‎"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎Enable support for experimental freeform windows.‎‏‎‎‏‎"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎Desktop mode‎‏‎‎‏‎"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎Desktop backup password‎‏‎‎‏‎"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎Desktop full backups aren’t currently protected‎‏‎‎‏‎"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‎Tap to change or remove the password for desktop full backups‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 9015ed5..ff9f7ae 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permitir que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Habilitar ventanas de forma libre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Permite la compatibilidad con ventanas de forma libre experimentales."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modo de escritorio"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Contraseñas"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Presiona para cambiar o quitar la contraseña de las copias de seguridad completas de tu escritorio."</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 4ee2753..abf60d8 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite que todas las actividades puedan cambiar de tamaño en multiventana independientemente de los valores de manifiesto"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Habilitar ventanas de forma libre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Permite la compatibilidad con ventanas de forma libre experimentales"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modo Escritorio"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Contraseña para copias de ordenador"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Las copias de seguridad completas de ordenador no están protegidas"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca para cambiar o quitar la contraseña de las copias de seguridad completas del escritorio"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 4667466..4e70a53 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Muudetakse kõigi tegevuste suurused mitme aknaga vaates muudetavaks (manifesti väärtustest olenemata)."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Luba vabas vormis aknad"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Lubatakse katseliste vabavormis akende tugi."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Lauaarvuti režiim"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Arvutivarunduse parool"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Täielikud arvutivarundused pole praegu kaitstud"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Puudutage täielike arvutivarunduste parooli muutmiseks või eemaldamiseks"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index d9c4ee7..8dd6007 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Eman aukera jarduera guztien tamaina doitzeko, hainbat leihotan erabili ahal izan daitezen, ezarritako balioak kontuan izan gabe"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Gaitu estilo libreko leihoak"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Onartu estilo libreko leiho esperimentalak"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Ordenagailuetarako modua"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Babeskopien pasahitz lokala"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ordenagailuko eduki guztiaren babeskopia egiteko erabiltzen den pasahitza aldatzeko edo kentzeko, sakatu hau"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1d53864..beaaa39 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"بدون توجه به مقادیر مانیفست، اندازه همه فعالیت‌ها برای حالت چند پنجره‌ای می‌تواند تغییر کند."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"فعال کردن پنجره‌های آزاد"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"فعال کردن پشتیبانی برای پنجره‌های آزاد آزمایشی."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"حالت رایانه"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"گذرواژه پشتیبان‌گیری محلی"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"پشتیبان‌گیری کامل رایانه درحال حاضر محافظت نمی‌شود"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"برای تغییر یا حذف گذرواژه برای نسخه‌های پشتیبان کامل رایانه‌ای ضربه بزنید"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 579771b..ec1c1f1 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Pakota kaikki toiminnot hyväksymään koon muuttaminen usean ikkunan tilassa luettelon arvoista riippumatta"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Ota käyttöön vapaamuotoiset ikkunat"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ota kokeellisten vapaamuotoisten ikkunoiden tuki käyttöön"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Työpöytätila"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Varmuuskop. salasana"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Vaihda tai poista tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla."</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f3c92e1..f48bfcb 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multi-fenêtre, indépendamment des valeurs du fichier manifeste."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Mode Bureau"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe sauvegarde PC"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Touchez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur ordinateur."</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 8e84b0b..ca5edfe 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Rendre toutes les activités redimensionnables pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Mode ordinateur"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe de sauvegarde ordi"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Les sauvegardes complètes sur ordi ne sont actuellement pas protégées"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Appuyez pour modifier ou supprimer le mot de passe des sauvegardes complètes sur ordi."</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index d78ab17..61b01f6 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite axustar o tamaño de todas as actividades para o modo multiventá, independentemente dos valores do manifesto"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activar ventás de forma libre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activa a compatibilidade con ventás de forma libre experimentais"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modo de escritorio"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Contrasinal para copias"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"As copias de seguranza de ordenador completas non están protexidas"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toca para cambiar ou quitar o contrasinal para as copias de seguranza completas de ordenador"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 2301bfd..981cf57 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -174,7 +174,7 @@
     <string name="launch_defaults_some" msgid="3631650616557252926">"કેટલાંક ડિફોલ્ટ્સ સેટ કરેલ છે"</string>
     <string name="launch_defaults_none" msgid="8049374306261262709">"કોઈ ડિફૉલ્ટ સેટ કરેલા નથી"</string>
     <string name="tts_settings" msgid="8130616705989351312">"ટેક્સ્ટ ટૂ સ્પીચ સેટિંગ"</string>
-    <string name="tts_settings_title" msgid="7602210956640483039">"ટેક્સ્ટ ટુ સ્પીચ આઉટપુટ"</string>
+    <string name="tts_settings_title" msgid="7602210956640483039">"ટેક્સ્ટ ટૂ સ્પીચ આઉટપુટ"</string>
     <string name="tts_default_rate_title" msgid="3964187817364304022">"સ્પીચ રેટ"</string>
     <string name="tts_default_rate_summary" msgid="3781937042151716987">"ટેક્સ્ટ બોલાયેલ છે તે ઝડપ"</string>
     <string name="tts_default_pitch_title" msgid="6988592215554485479">"પિચ"</string>
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"મૅનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, તમામ પ્રવૃત્તિઓને મલ્ટી-વિન્ડો માટે ફરીથી કદ બદલી શકે તેવી બનાવો."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ફ્રીફોર્મ વિન્ડો ચાલુ કરો"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"પ્રાયોગિક ફ્રીફોર્મ વિન્ડો માટે સપોર્ટને ચાલુ કરો."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ડેસ્કટૉપ મોડ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ડેસ્કટૉપ બૅકઅપ પાસવર્ડ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ડેસ્કટૉપ સંપૂર્ણ બૅકઅપ હાલમાં સુરક્ષિત નથી"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટૅચ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 363793c..9be1cd6 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"सभी गतिविधियों को मल्टी-विंडो (एक से ज़्यादा ऐप्लिकेशन, एक साथ) के लिए साइज़ बदलने लायक बनाएं, चाहे उनकी मेनिफ़ेस्ट वैल्यू कुछ भी हो."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"फ़्रीफ़ॉर्म विंडो (एक साथ कई विंडो दिखाना) चालू करें"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"फ़्रीफ़ॉर्म विंडो आज़माने की सुविधा चालू करें."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"डेस्कटॉप मोड"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"डेस्‍कटॉप बैकअप पासवर्ड"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"डेस्‍कटॉप का पूरा बैकअप फ़िलहाल सुरक्षित नहीं है"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटॉप के पूरे बैक अप का पासवर्ड बदलने या हटाने के लिए टैप करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 8be7676..8a0114a 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Omogući mijenjanje veličine svih aktivnosti za više prozora, neovisno o vrijednostima manifesta."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Omogući prozore slobodnog oblika"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogućuje podršku za eksperimentalne prozore slobodnog oblika."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Stolni način rada"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Zaporka sigurnosne kopije"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dodirnite da biste promijenili ili uklonili zaporku za potpune sigurnosne kopije na računalu"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 6885a07..b5e1e01 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Legyen az összes tevékenység átméretezhető a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Szabad formájú ablakok engedélyezése"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Kísérleti, szabad formájú ablakok támogatásának engedélyezése."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Asztali üzemmód"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Asztali mentés jelszava"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Koppintson ide az asztali teljes mentések jelszavának módosításához vagy eltávolításához"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index c77769e..9808f70 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Ակտիվացնել կամայական ձևի պատուհանները"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Միացնել ազատ ձևի փորձնական պատուհանների աջակցումը:"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Համակարգչի ռեժիմ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Հպեք՝ աշխատասեղանի ամբողջական պահուստավորման գաղտնաբառը փոխելու կամ հեռացնելու համար"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2168e8f..7d70b88 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Aktifkan jendela berformat bebas"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktifkan dukungan untuk jendela eksperimental berformat bebas."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Mode desktop"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Sandi cadangan desktop"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketuk guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 46eb90c..650f76d 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gera stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Virkja glugga með frjálsu sniði"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Virkja stuðning við glugga með frjálsu sniði á tilraunastigi."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Skjáborðsstilling"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Aðgangsorð tölvuafritunar"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ýttu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index bbe0412..d783bf1 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Rendi il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Attiva finestre a forma libera"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Attiva il supporto delle finestre a forma libera sperimentali"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modalità desktop"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Password di backup desktop"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"I backup desktop completi non sono attualmente protetti"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 85e3a53..fc83630 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא התחשבות בערכי המניפסט."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"הפעלת האפשרות לשנות את הגודל והמיקום של החלונות"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"הפעלת תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ממשק המחשב"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"סיסמת גיבוי שולחן העבודה"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"יש להקיש כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 71e70ba..3f09083 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようにします。"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"フリーフォーム ウィンドウを有効にする"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"試験運用機能のフリーフォーム ウィンドウのサポートを有効にします。"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"デスクトップ モード"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"PC バックアップ パスワード"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"デスクトップのフルバックアップは現在保護されていません"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index fa7db4a..ed7c8d7 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"მანიფესტის მნიშვნელობების მიუხედავად, მრავალი ფანჯრის რეჟიმისთვის ყველა აქტივობის ზომაცვლადად გადაქცევა."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"თავისუფალი ფორმის მქონე ფანჯრების ჩართვა"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"თავისუფალი ფორმის მქონე ფანჯრების მხარდაჭერის ექსპერიმენტული ფუნქციის ჩართვა."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"დესკტოპის რეჟიმი"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index efac4e8..982000f 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Манифест мәндеріне қарамастан, бірнеше терезе режимінде барлық әрекеттердің өлшемін өзгертуге рұқсат беру"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Еркін пішінді терезелерге рұқсат беру"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Еркін пішінді терезелерді құру эксперименттік функиясын қосу"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Компьютер режимі"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Компьютердегі сақтық көшірме құпия сөзі"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Компьютердегі толық сақтық көшірмелер қазір қорғалмаған."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Үстелдік компьютердің толық сақтық көшірмелерінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 11c71ca..26bb1e2 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ធ្វើឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសថ៍។"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"បើកដំណើរការផ្ទាំងវិនដូទម្រង់សេរី"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"បើកឱ្យអាចប្រើផ្ទាំងវិនដូទម្រង់សេរីពិសោធន៍។"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"មុខងារកុំព្យូទ័រ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ពាក្យ​សម្ងាត់​បម្រុង​ទុក​លើកុំព្យូទ័រ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"បច្ចុប្បន្ន ការ​បម្រុង​ទុក​ពេញលេញនៅលើកុំព្យូទ័រមិន​ត្រូវ​បាន​ការពារ​ទេ"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ប៉ះដើម្បីប្ដូរ ឬយកពាក្យសម្ងាត់ចេញសម្រាប់ការបម្រុងទុកពេញលេញលើកុំព្យូទ័រ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index fa3dbaf..5a09396 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡಿ."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ಪ್ರಾಯೋಗಿಕ ಫ್ರೀಫಾರ್ಮ್ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ಡೆಸ್ಕ್‌ಟಾಪ್ ಮೋಡ್"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ಡೆಸ್ಕ್‌ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್‌ವರ್ಡ್"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ಡೆಸ್ಕ್‌ಟಾಪ್‌‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌‌ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್‌ ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index f484133..1c5fd76 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"자유 형식 창 사용"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"자유 형식 창 지원 사용"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"데스크톱 모드"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"데스크톱 백업 비밀번호"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 탭하세요."</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index bde9b08..4ad4306 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Бир нече терезе режиминде өлчөмдү өзгөртүүгө уруксат берет (манифесттин маанилерине карабастан)"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Эркин формадагы терезелерди түзүүнү иштетүү"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Эркин формадагы терезелерди түзүү боюнча сынамык функциясы иштетилет."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Компьютер режими"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Камдык көчүрмөнүн сырсөзү"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Толук камдык көчүрмөлөр учурда корголгон эмес"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Иш тактасынын камдалган сырсөзүн өзгөртүү же алып салуу үчүн таптап коюңуз"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 2f4e7ff..fe8b4db 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ເຮັດໃຫ້ທຸກການ​ເຄື່ອນ​ໄຫວສາມາດປັບຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຈໍ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າ manifest."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ເປີດໃຊ້ໜ້າຈໍຮູບແບບອິດສະຫຼະ"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ເປີດໃຊ້ການຮອງຮັບໜ້າຈໍຮູບແບບອິດສະຫຼະແບບທົດລອງ."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ໂໝດເດັສທັອບ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັສທັອບ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ການ​ສຳຮອງ​ຂໍ້ມູນ​ເຕັມຮູບແບບ​ໃນ​ເດັສທັອບ​ຍັງ​ບໍ່​ໄດ້​ຮັບ​ການ​ປ້ອງກັນ​ໃນ​ເວລາ​ນີ້"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ແຕະເພື່ອປ່ຽນ ຫຼື ລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັສທັອບ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 59ab47b..e4546e1 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Nustatyti, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Įgalinti laisvos formos langus"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Įgalinti eksperimentinių laisvos formos langų palaikymą."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Stalinio komp. režimas"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Viet. atsrg. kop. slapt."</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Jei norite pakeisti ar pašalinti visų stalinio kompiuterio atsarginių kopijų slaptažodį, palieskite"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index a04bd54..e9410a2 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Pielāgot visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Iespējot brīvās formas logus"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Iespējot eksperimentālo brīvās formas logu atbalstu."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Darbvirsmas režīms"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Datora dublējuma parole"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem datora dublējumiem."</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 37a448f..4866e6a 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Сите активности ќе имаат променлива големина во режимот со повеќе прозорци, независно од вредностите на манифестот."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Овозможи прозорци со слободна форма"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Овозможи поддршка за експериментални прозорци со слободна форма."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Режим за компјутер"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Лозинка за бекап на компјутер"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Целосниот бекап на компјутерот во моментов не е заштитен"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Допрете за да се промени или отстрани лозинката за целосен бекап на компјутерот"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 452a995..78a3968 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ ആക്ടിവിറ്റികളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലുപ്പം മാറ്റുക."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ഫ്രീഫോം വിൻഡോകൾ പ്രവർത്തനക്ഷമമാക്കുക"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"പരീക്ഷണാത്മക ഫ്രീഫോം വിൻഡോകൾക്കുള്ള പിന്തുണ പ്രവർത്തനക്ഷമമാക്കുക."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ഡെസ്‌ക്ടോപ്പ് മോഡ്"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ഡെ‌സ്‌ക്ടോപ്പ് ബാക്കപ്പ് പാസ്‌വേഡ്"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്‌വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ ടാപ്പുചെയ്യുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 6dfce5a..31f190d 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Чөлөөт хэлбэрийн цонхыг идэвхжүүлэх"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Туршилтын чөлөөт хэлбэрийн цонхны дэмжлэгийг идэвхжүүлнэ үү."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Дэлгэцийн горим"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Компьютерын нөөцлөлтийн нууц үг"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Компьютерын бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Компьютерийн бүтэн нөөцлөлтийн нууц үгийг өөрчлөх, устгах бол дарна уу"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 4db523a..e5852ed 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"मॅनिफेस्‍ट मूल्ये काहीही असू देत, एकाहून अधिक विंडोसाठी सर्व अ‍ॅक्टिव्हिटीचा आकार बदलण्यायोग्य करा."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"freeform windows सुरू करा"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रायोगिक freeform windows साठी सपोर्ट सुरू करा."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"डेस्कटॉप मोड"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटॉप बॅकअप पासवर्ड"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला पासवर्ड बदलण्यासाठी किंवा काढण्यासाठी टॅप  करा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index ef21812..ca07d2b 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Bolehkan semua saiz aktiviti diubah untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Dayakan tetingkap bentuk bebas"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Dayakan sokongan untuk tetingkap bentuk bebas percubaan."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Mod desktop"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Kata laluan sandaran komputer meja"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketik untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh desktop"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2e4a6c4..0b9b3d1 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"သတ်မှတ်တန်ဖိုး မည်သို့ပင်ရှိစေ ဝင်းဒိုးများ၏ လုပ်ဆောင်မှုအားလုံးကို အရွယ်အစားပြင်သည်။"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ပုံစံမျိုးစုံ ဝင်းဒိုးများ ဖွင့်ရန်"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ပုံစံမျိုးစုံဝင်းဒိုးများ စမ်းသပ်ခြင်းအတွက် ပံ့ပိုးမှုကို ဖွင့်သည်"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ဒက်စ်တော့မုဒ်"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ဒက်စ်တော့ အရန်စကားဝှက်"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ဒက်စ်တော့ အရန်သိမ်းဆည်းခြင်းအားလုံးကို လောလောဆယ် ကာကွယ်မထားပါ"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ဒက်စ်တော့ အပြည့်အဝ အရန်သိမ်းခြင်းအတွက် စကားဝှက်ကို ပြောင်းရန် သို့မဟုတ် ဖယ်ရှားရန် တို့ပါ။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index e871ab9..e68a2b7 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gjør at alle aktiviteter kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Slå på vinduer i fritt format"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Slå på støtte for vinduer i eksperimentelt fritt format."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Skrivebordmodus"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Passord for sikkerhetskopiering på datamaskin"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Fullstendig sikkerhetskopiering på datamaskin er ikke beskyttet"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index a48dd1e..e52b880 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"तोकिएको नियमको ख्याल नगरी एपलाई एकभन्दा बढी विन्डोमा रिसाइज गर्न सकिने बनाइयोस्।"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"फ्रिफर्म विन्डोहरू अन गरियोस्"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"प्रयोगात्मक फ्रिफर्म विन्डोहरू चल्ने बनाइयोस्"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"डेस्कटप मोड"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"डेस्कटप ब्याकअप पासवर्ड"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"हाल डेस्कटपका सबै ब्याकअप पासवर्ड सुरक्षित छैनन्"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन ट्याप गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index dfc3389..0d52d9d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Maak het formaat van alle activiteiten aanpasbaar, ongeacht de manifestwaarden"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Vensters met vrije vorm aanzetten"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Zet ondersteuning voor vensters met experimentele vrije vorm aan"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktopmodus"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Wachtwoord desktopback-up"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tik om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index a29fb0f..eb54cba 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ମାନିଫେଷ୍ଟ ମୂଲ୍ୟ ଯାହା ହୋଇଥାଉ ନା କାହିଁକି, ଏକାଧିକ-ୱିଣ୍ଡୋ ପାଇଁ ସମସ୍ତ କାର୍ଯ୍ୟକଳାପକୁ ରିସାଇଜ କରନ୍ତୁ।"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ଫ୍ରିଫର୍ମ ୱିଣ୍ଡୋକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ପରୀକ୍ଷାମୂଳକ ଫ୍ରିଫର୍ମ ୱିଣ୍ଡୋଗୁଡ଼ିକ ପାଇଁ ସପୋର୍ଟକୁ ସକ୍ଷମ କରନ୍ତୁ।"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ଡେସ୍କଟପ ମୋଡ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ଡେସ୍କଟପ ବେକଅପ ପାସୱାର୍ଡ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ଡେସ୍କଟପ୍‌ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍‌ଗୁଡ଼ିକ ବର୍ତ୍ତମାନ ସୁରକ୍ଷିତ ନୁହେଁ"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ଡେସ୍କଟପ୍‌ର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକ୍‌ଅପ୍‌ ପାଇଁ ପାସ୍‌ୱର୍ଡ ବଦଳାଇବା କିମ୍ୱା କାଢ଼ିଦେବା ନିମନ୍ତେ ଟାପ୍‌ କରନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 917d5f8..b0faa80 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ਮੈਨੀਫ਼ੈਸਟ ਮੁੱਲਾਂ ਦੀ ਪਰਵਾਹ ਕੀਤੇ ਬਿਨਾਂ, ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਆਕਾਰ ਬਦਲਣਯੋਗ ਬਣਾਓ।"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ਪ੍ਰਯੋਗਮਈ ਫ੍ਰੀਫਾਰਮ ਵਿੰਡੋਜ਼ ਲਈ ਸਮਰਥਨ ਨੂੰ ਚਾਲੂ ਕਰੋ।"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ਡੈਸਕਟਾਪ ਮੋਡ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ਡੈਸਕਟਾਪ ਬੈਕਅੱਪ ਪਾਸਵਰਡ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ਡੈਸਕਟਾਪ ਦੇ ਪੂਰੇ ਬੈਕਅੱਪ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ਡੈਸਕਟਾਪ ਦੇ ਮੁਕੰਮਲ ਬੈਕਅੱਪਾਂ ਲਈ ਪਾਸਵਰਡ ਨੂੰ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 0bf5b70..cdc5ba2 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Zezwalaj na zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Włącz dowolny rozmiar okien"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Włącz obsługę eksperymentalnej funkcji dowolnego rozmiaru okien"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Tryb pulpitu"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Hasło kopii zapasowej"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dotknij, by zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 9af28a6..f1784bc 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas experimentais de forma livre"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modo área de trabalho"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Senha de backup local"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Os backups completos não estão protegidos no momento"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 53221ed..c510e2b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas de forma livre experimentais."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Ambiente de trabalho"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Palavra-passe cópia do computador"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tocar para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 9af28a6..f1784bc 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Tornar todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Ativar janelas de forma livre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ativar a compatibilidade com janelas experimentais de forma livre"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modo área de trabalho"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Senha de backup local"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Os backups completos não estão protegidos no momento"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index db0993e..447bb63 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activează ferestrele cu formă liberă"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activează compatibilitatea pentru ferestrele experimentale cu formă liberă."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modul desktop"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Parolă backup computer"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"În prezent, backupurile complete pe computer nu sunt protejate"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Atinge ca să modifici sau să elimini parola pentru backupurile complete pe desktop"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index e9f7b0a..f10e8e7 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Разрешить изменение размера окон в многооконном режиме (независимо от значений в манифесте)"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Разрешить создание окон произвольной формы"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Включить экспериментальную функцию создания окон произвольной формы"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Режим компьютера"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Пароль для резервного копирования"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Полные локальные резервные копии в настоящее время не защищены"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Нажмите, чтобы изменить или удалить пароль для резервного копирования"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index d3bdd56..51bd3c1 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළුව සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරන්න."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"අනියම් හැඩැති කවුළු සබල කරන්න"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"පරීක්ෂණාත්මක අනියම් හැඩැති කවුළු සඳහා සහාය සබල කරන්න."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ඩෙස්ක්ටොප් ප්‍රකාරය"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට තට්ටු කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b34fe9d..6918728 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Umožniť zmeniť veľkosť všetkých aktivít na niekoľko okien (bez ohľadu na hodnoty manifestu)"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Povoliť okná s voľným tvarom"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Povoliť podporu pre experimentálne okná s voľným tvarom"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Režim počítača"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Heslo pre zálohy v počítači"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Úplné zálohy v počítači nie sú momentálne chránené"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Klepnutím zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index b142a6c..cf174e1 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim spremeniti velikost za način z več okni."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Omogoči okna svobodne oblike"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Omogoči podporo za poskusna okna svobodne oblike."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Namizni način"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Geslo za varnostno kopijo namizja"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Popolne varnostne kopije namizja trenutno niso zaščitene."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b27b6bd..7802704 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Bëj që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivizo dritaret me formë të lirë"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivizo mbështetjen për dritaret eksperimentale me formë të lirë."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Modaliteti i desktopit"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Fjalëkalimi rezervë i kompjuterit"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Trokit për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 286e908..eb10b55 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Омогући прозоре произвољног формата"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Омогућава подршку за експерименталне прозоре произвољног формата."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Режим за рачунаре"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Лозинка резервне копије за рачунар"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Резервне копије читавог система тренутно нису заштићене"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index e2f7017..256b4e9 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Aktivera frihandsfönster"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Aktivera stöd för experimentella frihandsfönster."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Datorläge"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Lösenord för säkerhetskopia av datorn"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f66684a..e23dbcb 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwenye madirisha mengi, bila kuzingatia thamani za faili ya maelezo."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Washa madirisha yenye muundo huru"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Ruhusu uwezo wa kutumia madirisha ya majaribio yenye muundo huru."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Hali ya kompyuta ya mezani"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 22d4feb..365c3da 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமை."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"குறிப்பிட்ட வடிவமில்லாத சாளரங்களை இயக்கு"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"சாளரங்களை அளவுமாற்ற மற்றும் எங்கும் நகர்த்த அனுமதிக்கும் பரிசோதனைக்குரிய அம்சத்திற்கான ஆதரவை இயக்கு."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"டெஸ்க்டாப் பயன்முறை"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"டெஸ்க்டாப்பின் முழுக் காப்புப் பிரதிகளுக்கான கடவுச்சொல்லை மாற்ற அல்லது அகற்ற, தட்டவும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index dc5bacd..d1c464c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని యాక్టివిటీస్‌ను పలు రకాల విండోల్లో సరిపోయేటట్లు సైజ్‌ మార్చగలిగేలా చేస్తుంది."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"స్వతంత్ర రూప విండోలను ఎనేబుల్ చేయండి"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"ప్రయోగాత్మక స్వతంత్ర రూప విండోల కోసం సపోర్ట్‌ను ఎనేబుల్ చేస్తుంది."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"డెస్క్‌టాప్ మోడ్"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"డెస్క్‌టాప్ బ్యాకప్ పాస్‌వర్డ్"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌లు ప్రస్తుతం రక్షించబడలేదు"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 7dd346a..bc6840b 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"เปิดใช้หน้าต่างรูปแบบอิสระ"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"เปิดการสนับสนุนหน้าต่างรูปแบบอิสระแบบทดลอง"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"โหมดเดสก์ท็อป"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อปไม่ได้รับการป้องกันในขณะนี้"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"แตะเพื่อเปลี่ยนแปลงหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8ad8fd7..4360b9f 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Gawing nare-resize ang lahat ng aktibidad para sa multi-window, anuman ang mga value ng manifest."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"I-enable ang mga freeform window"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"I-enable ang suporta para sa mga pang-eksperimentong freeform window."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktop mode"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Password ng pag-backup ng desktop"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"I-tap upang baguhin o alisin ang password para sa mga kumpletong pag-back up sa desktop"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 0af470d..206df8f 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir yap."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Serbest biçimli pencereleri etkinleştir"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Deneysel serbest biçimli pencere desteğini etkinleştir."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Masaüstü modu"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Masaüstü yedekleme şifresi"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 3b84923..2bc80df 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Масштабувати активність на кілька вікон, незалежно від значень у файлі маніфесту."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Увімкнути вікна довільного формату"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Увімкнути експериментальні вікна довільного формату."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Режим комп’ютера"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Пароль рез. копії на ПК"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Повні резервні копії на комп’ютері наразі не захищені"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Торкніться, щоб змінити або видалити пароль для повного резервного копіювання на комп’ютер"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 9f7d18e..b8bef4c 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"مینی فیسٹ اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بنائیں۔"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"‏freeform ونڈوز فعال کریں"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"تجرباتی فری فارم ونڈوز کیلئے سپورٹ فعال کریں۔"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"ڈیسک ٹاپ موڈ"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے تھپتھپائیں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index b9c17fc..57c59e1 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtirish."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Erkin shakldagi oynalarni yoqish"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Erkin shakldagi oynalar yaratish uchun mo‘ljallangan tajribaviy funksiyani yoqish."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Desktop rejimi"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Zaxira nusxa uchun parol"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ish stoli to‘liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 0eaaf21..9877249 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Cho phép thay đổi kích thước của tất cả các hoạt động cho nhiều cửa sổ, bất kể giá trị tệp kê khai là gì."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Bật cửa sổ dạng tự do"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Bật tính năng hỗ trợ cửa sổ dạng tự do thử nghiệm."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Chế độ máy tính"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Mật khẩu cho bản sao lưu qua máy tính"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Các bản sao lưu đầy đủ qua máy tính hiện không được bảo vệ"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Nhấn để thay đổi hoặc xóa mật khẩu dành cho các bản sao lưu đầy đủ vào máy tính"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 74ab016e..a210e6c 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"将所有 activity 设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"启用可自由调整的窗口"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"启用可自由调整的窗口这一实验性功能。"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"桌面模式"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"桌面备份密码"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"桌面完整备份当前未设置密码保护"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"点按即可更改或移除用于保护桌面完整备份的密码"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 21f6d51..f78b141 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"在任何資訊清單值下,允許系統配合多重視窗環境調整所有活動的尺寸。"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"啟用自由形態視窗"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"啟用實驗版自由形態視窗的支援功能。"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"桌面模式"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"桌面電腦備份密碼"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"桌面電腦的完整備份目前未受保護"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"輕按即可變更或移除桌面電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 09f8d13..a66a029 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"啟用自由形式視窗"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"啟用實驗版自由形式視窗的支援功能。"</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"電腦模式"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"電腦備份密碼"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"目前尚未設定密碼來保護完整的備份檔案 (透過電腦備份的檔案)"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"輕觸即可變更或移除電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 5de118c..45b8c54 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -403,7 +403,6 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Yenza yonke imisebenzi ibe nosayizi abasha kumawindi amaningi, ngokunganaki amavelu e-manifest."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Nika amandla amawindi e-freeform"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Nika amandla usekelo lwe-windows yokuhlola kwe-freeform."</string>
-    <string name="desktop_mode" msgid="2389067840550544462">"Imodi yedeskithophu"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Thepha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0acce03..ec24ab7 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -954,9 +954,6 @@
     <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
     <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
 
-    <!-- UI debug setting: enable desktop mode [CHAR LIMIT=25] -->
-    <string name="desktop_mode">Desktop mode</string>
-
     <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
     <string name="local_backup_password_title">Desktop backup password</string>
     <!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index af06d73..b1d1ea5e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -126,10 +126,10 @@
             switchSummary = isChecked()
                     ? getUpdatableEnterpriseString(
                             getContext(), ENABLED_BY_ADMIN_SWITCH_SUMMARY,
-                            R.string.enabled_by_admin)
+                            com.android.settingslib.widget.R.string.enabled_by_admin)
                     : getUpdatableEnterpriseString(
                             getContext(), DISABLED_BY_ADMIN_SWITCH_SUMMARY,
-                            R.string.disabled_by_admin);
+                            com.android.settingslib.widget.R.string.disabled_by_admin);
         } else {
             switchSummary = mRestrictedSwitchSummary;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 6eb2f38..96bb4b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1776,7 +1776,8 @@
             final int userId = UserHandle.getUserId(this.info.uid);
             if (UserManager.get(context).isManagedProfile(userId)) {
                 this.labelDescription = context.getString(
-                        com.android.settingslib.R.string.accessibility_work_profile_app_description,
+                        com.android.settingslib.utils.R
+                                .string.accessibility_work_profile_app_description,
                         this.label);
             } else {
                 this.labelDescription = this.label;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java
index cb4eba4..f5257b0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java
@@ -46,7 +46,8 @@
         View layout = View.inflate(mContext, R.layout.broadcast_dialog, null);
         final Window window = getWindow();
         window.setContentView(layout);
-        window.setWindowAnimations(R.style.Theme_AlertDialog_SettingsLib);
+        window.setWindowAnimations(
+                com.android.settingslib.widget.R.style.Theme_AlertDialog_SettingsLib);
 
         TextView title = layout.findViewById(R.id.dialog_title);
         TextView subTitle = layout.findViewById(R.id.dialog_subtitle);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 00397f0..64c271b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -760,6 +760,14 @@
     void onAudioModeChanged() {
         dispatchAttributesChanged();
     }
+
+    /**
+     * Notify that the audio category has changed.
+     */
+    public void onAudioDeviceCategoryChanged() {
+        dispatchAttributesChanged();
+    }
+
     /**
      * Get the device status as active or non-active per Bluetooth profile.
      *
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
index 5e66972..7669e79b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
@@ -3,7 +3,10 @@
 hughchen@google.com
 timhypeng@google.com
 robertluo@google.com
-changbetty@google.com
 songferngwang@google.com
+yqian@google.com
+chelseahao@google.com
+yiyishen@google.com
+hahong@google.com
 
 # Emergency approvers in case the above are not available
diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
index 1f4cafce..d53c3a7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java
@@ -153,7 +153,7 @@
         }
         final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
         final int iconSize = getContext().getResources().getDimensionPixelSize(
-                R.dimen.secondary_app_icon_size);
+                com.android.settingslib.widget.R.dimen.secondary_app_icon_size);
         if (icon != null && iconSize > 0) {
             ViewGroup.LayoutParams params = icon.getLayoutParams();
             params.height = iconSize;
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
index ebdfbea..251cd36 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
@@ -32,7 +32,6 @@
 import android.util.Log;
 
 import com.android.launcher3.icons.BaseIconFactory;
-import com.android.settingslib.R;
 import com.android.settingslib.Utils;
 
 /**
@@ -81,7 +80,7 @@
         mPackageManager = pm;
         mIconDrawableFactory = iconDrawableFactory;
         mImportantConversationColor = context.getResources().getColor(
-                R.color.important_conversation, null);
+                com.android.launcher3.icons.R.color.important_conversation, null);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java
index 5c48c54..6b855c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeGenerator.java
@@ -31,6 +31,7 @@
 import java.util.Map;
 
 public final class QrCodeGenerator {
+    private static final int DEFAULT_MARGIN = -1;
     /**
      * Generates a barcode image with {@code contents}.
      *
@@ -40,7 +41,20 @@
      */
     public static Bitmap encodeQrCode(String contents, int size)
             throws WriterException, IllegalArgumentException {
-        return encodeQrCode(contents, size, /*invert=*/false);
+        return encodeQrCode(contents, size, DEFAULT_MARGIN, /*invert=*/false);
+    }
+
+    /**
+     * Generates a barcode image with {@code contents}.
+     *
+     * @param contents The contents to encode in the barcode
+     * @param size     The preferred image size in pixels
+     * @param margin   The margin around the actual barcode
+     * @return Barcode bitmap
+     */
+    public static Bitmap encodeQrCode(String contents, int size, int margin)
+            throws WriterException, IllegalArgumentException {
+        return encodeQrCode(contents, size, margin, /*invert=*/false);
     }
 
     /**
@@ -53,10 +67,27 @@
      */
     public static Bitmap encodeQrCode(String contents, int size, boolean invert)
             throws WriterException, IllegalArgumentException {
+        return encodeQrCode(contents, size, DEFAULT_MARGIN, /*invert=*/invert);
+    }
+
+    /**
+     * Generates a barcode image with {@code contents}.
+     *
+     * @param contents The contents to encode in the barcode
+     * @param size     The preferred image size in pixels
+     * @param margin   The margin around the actual barcode
+     * @param invert   Whether to invert the black/white pixels (e.g. for dark mode)
+     * @return Barcode bitmap
+     */
+    public static Bitmap encodeQrCode(String contents, int size, int margin, boolean invert)
+            throws WriterException, IllegalArgumentException {
         final Map<EncodeHintType, Object> hints = new HashMap<>();
         if (!isIso88591(contents)) {
             hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
         }
+        if (margin != DEFAULT_MARGIN) {
+            hints.put(EncodeHintType.MARGIN, margin);
+        }
 
         final BitMatrix qrBits = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE,
                 size, size, hints);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index 21eb35a..2d6f058 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -167,7 +167,8 @@
         ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
         bindFrictionImage(frictionImageView);
 
-        final View divider = view.findViewById(R.id.two_target_divider);
+        final View divider =
+                view.findViewById(com.android.settingslib.widget.R.id.two_target_divider);
         divider.setVisibility(shouldShowDivider() ? View.VISIBLE : View.INVISIBLE);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index c45d774..015356e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -331,7 +331,8 @@
                 return;
             } else if (!isDefaultNetwork && mDefaultNetworkCapabilities != null
                     && mDefaultNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
-                statusLabel = mContext.getString(R.string.wifi_connected_low_quality);
+                statusLabel = mContext.getString(
+                        com.android.wifitrackerlib.R.string.wifi_connected_low_quality);
                 return;
             }
         }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
index 74c2fc8..32a16716 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
@@ -54,7 +54,7 @@
         mPreference = new PrimarySwitchPreference(mContext);
         LayoutInflater inflater = LayoutInflater.from(mContext);
         mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
-                com.android.settingslib.R.layout.preference_two_target, null));
+                com.android.settingslib.widget.R.layout.preference_two_target, null));
         mWidgetView = mHolder.itemView.findViewById(android.R.id.widget_frame);
         inflater.inflate(R.layout.preference_widget_primary_switch, mWidgetView, true);
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java
index 06343f5..ff84dc9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayoutTest.java
@@ -55,7 +55,8 @@
     @Test
     public void onCreate_userAddedChildViewsBeMovedToContentFrame() {
         CollapsingCoordinatorLayout layout = mActivity.getCollapsingCoordinatorLayout();
-        View contentFrameView = layout.findViewById(R.id.content_frame);
+        View contentFrameView =
+                layout.findViewById(com.android.settingslib.widget.R.id.content_frame);
 
         TextView textView = contentFrameView.findViewById(R.id.text_hello_world);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
index 471dac0..8246aff 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
@@ -29,8 +29,6 @@
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -95,7 +93,7 @@
         @Override
         protected void onCreate(@Nullable Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-            setTheme(R.style.Theme_AppCompat);
+            setTheme(androidx.appcompat.R.style.Theme_AppCompat);
             getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
         }
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminControllerTest.java
index 7b08fee..2f8967e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminControllerTest.java
@@ -30,8 +30,6 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,7 +49,7 @@
 
     @Before
     public void setUp() {
-        mActivity.setTheme(R.style.Theme_AppCompat_DayNight);
+        mActivity.setTheme(androidx.appcompat.R.style.Theme_AppCompat_DayNight);
 
         mController.initialize(mTestUtils.createLearnMoreButtonLauncher());
         mController.updateEnforcedAdmin(ENFORCED_ADMIN, ENFORCEMENT_ADMIN_USER_ID);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
index 7b88566..f168122 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminControllerTest.java
@@ -33,8 +33,6 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,7 +55,7 @@
 
     @Before
     public void setUp() {
-        mActivity.setTheme(R.style.Theme_AppCompat_DayNight);
+        mActivity.setTheme(androidx.appcompat.R.style.Theme_AppCompat_DayNight);
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
index 66a2ea6..6831222 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java
@@ -62,7 +62,7 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mActivity = spy(ActivityController.of(new FragmentActivity()).get());
-        mActivity.setTheme(R.style.Theme_AppCompat_DayNight);
+        mActivity.setTheme(androidx.appcompat.R.style.Theme_AppCompat_DayNight);
         mUnderTest = new TestCreateUserDialogController();
         mPhotoRestrictedByBase = false;
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
index f595cd3..a95257a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
@@ -99,7 +99,7 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mActivity = spy(ActivityController.of(new FragmentActivity()).get());
-        mActivity.setTheme(R.style.Theme_AppCompat_DayNight);
+        mActivity.setTheme(androidx.appcompat.R.style.Theme_AppCompat_DayNight);
         mController = new TestEditUserInfoController();
         mPhotoRestrictedByBase = false;
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java
index 6cbae05..10862403 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveIconTest.java
@@ -105,15 +105,15 @@
 
         icon.setBackgroundColor(mContext, tile);
 
-        assertThat(icon.mBackgroundColor)
-                .isEqualTo(mContext.getColor(R.color.homepage_generic_icon_background));
+        assertThat(icon.mBackgroundColor).isEqualTo(mContext.getColor(
+                com.android.settingslib.widget.R.color.homepage_generic_icon_background));
     }
 
     @Test
     public void onBindTile_externalTileWithBackgroundColorHint_shouldUpdateIcon() {
         final Tile tile = spy(new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
         mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON_BACKGROUND_HINT,
-                R.color.bt_outline_color);
+                com.android.settingslib.widget.R.color.bt_outline_color);
         doReturn(Icon.createWithResource(mContext, R.drawable.ic_system_update))
                 .when(tile).getIcon(mContext);
 
@@ -121,8 +121,8 @@
                 new AdaptiveIcon(mContext, new ColorDrawable(Color.BLACK));
         icon.setBackgroundColor(mContext, tile);
 
-        assertThat(icon.mBackgroundColor)
-                .isEqualTo(mContext.getColor(R.color.bt_outline_color));
+        assertThat(icon.mBackgroundColor).isEqualTo(mContext.getColor(
+                com.android.settingslib.widget.R.color.bt_outline_color));
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveOutlineDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveOutlineDrawableTest.java
index 71d55bc..b2bc53d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveOutlineDrawableTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AdaptiveOutlineDrawableTest.java
@@ -21,8 +21,6 @@
 import android.content.res.Resources;
 import android.graphics.Paint;
 
-import com.android.settingslib.R;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 049c90e..a26f200 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -58,14 +58,15 @@
     @Test
     public void setLearnMoreText_shouldSetAsTextInLearnMore() {
         final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null));
+                LayoutInflater.from(mContext)
+                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null));
         mFooterPreference.setLearnMoreText("Custom learn more");
         mFooterPreference.setLearnMoreAction(view -> { /* do nothing */ } /* listener */);
 
         mFooterPreference.onBindViewHolder(holder);
 
         assertThat(((TextView) holder.findViewById(
-                R.id.settingslib_learn_more)).getText().toString())
+                com.android.settingslib.widget.R.id.settingslib_learn_more)).getText().toString())
                 .isEqualTo("Custom learn more");
     }
 
@@ -94,8 +95,9 @@
     @Test
     public void onBindViewHolder_whenTitleIsNull_shouldNotRaiseNpe() {
         PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null)));
-        when(viewHolder.findViewById(R.id.title)).thenReturn(null);
+                LayoutInflater.from(mContext)
+                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null)));
+        when(viewHolder.findViewById(androidx.core.R.id.title)).thenReturn(null);
 
         Throwable actualThrowable = null;
         try {
@@ -110,8 +112,10 @@
     @Test
     public void onBindViewHolder_whenLearnMoreIsNull_shouldNotRaiseNpe() {
         PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null)));
-        when(viewHolder.findViewById(R.id.settingslib_learn_more)).thenReturn(null);
+                LayoutInflater.from(mContext)
+                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null)));
+        when(viewHolder.findViewById(com.android.settingslib.widget.R.id.settingslib_learn_more))
+                .thenReturn(null);
 
         Throwable actualThrowable = null;
         try {
@@ -126,7 +130,8 @@
     @Test
     public void onBindViewHolder_whenIconFrameIsNull_shouldNotRaiseNpe() {
         PreferenceViewHolder viewHolder = spy(PreferenceViewHolder.createInstanceForTests(
-                LayoutInflater.from(mContext).inflate(R.layout.preference_footer, null)));
+                LayoutInflater.from(mContext)
+                        .inflate(com.android.settingslib.widget.R.layout.preference_footer, null)));
         when(viewHolder.findViewById(R.id.icon_frame)).thenReturn(null);
 
         Throwable actualThrowable = null;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/TwoTargetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/TwoTargetPreferenceTest.java
index aaec909..23b4c2a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/TwoTargetPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/TwoTargetPreferenceTest.java
@@ -32,8 +32,6 @@
 
 import androidx.preference.PreferenceViewHolder;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index fa2d677..1d25ac7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -106,5 +106,10 @@
         Settings.Global.Wearable.RTL_SWIPE_TO_DISMISS_ENABLED_DEV,
         Settings.Global.Wearable.REDUCE_MOTION,
         Settings.Global.Wearable.WEAR_LAUNCHER_UI_MODE,
+        Settings.Global.Wearable.USER_HFP_CLIENT_SETTING,
+        Settings.Global.Wearable.RSB_WAKE_ENABLED,
+        Settings.Global.Wearable.SCREENSHOT_ENABLED,
+        Settings.Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED,
+        Settings.Global.Wearable.CHARGING_SOUNDS_ENABLED,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 8787c25..94a3173 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -165,12 +165,10 @@
         Settings.Secure.CHARGING_VIBRATION_ENABLED,
         Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
         Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
-        Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
         Settings.Secure.UI_NIGHT_MODE,
         Settings.Secure.UI_NIGHT_MODE_CUSTOM_TYPE,
         Settings.Secure.DARK_THEME_CUSTOM_START_TIME,
         Settings.Secure.DARK_THEME_CUSTOM_END_TIME,
-        Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
         Settings.Secure.SKIP_DIRECTION,
         Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
         Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 6b0a906..248c60c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -61,7 +61,7 @@
         Settings.System.TTY_MODE,
         Settings.System.MASTER_MONO,
         Settings.System.MASTER_BALANCE,
-        Settings.System.STAY_AWAKE_ON_FOLD,
+        Settings.System.FOLD_LOCK_BEHAVIOR,
         Settings.System.SOUND_EFFECTS_ENABLED,
         Settings.System.HAPTIC_FEEDBACK_ENABLED,
         Settings.System.POWER_SOUNDS_ENABLED,       // moved to global
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index dfc3cef..8179998 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -245,9 +245,7 @@
                 Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.TRUST_AGENTS_EXTEND_UNLOCK, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, JSON_OBJECT_VALIDATOR);
-        VALIDATORS.put(Secure.LOCK_SCREEN_WHEN_TRUST_LOST, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.SKIP_GESTURE, BOOLEAN_VALIDATOR);
         /*
          * Only used if FeatureFlag "settings_skip_direction_mutable" is enabled.
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 20740dc..17ce7c7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -134,6 +134,7 @@
         VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
+        VALIDATORS.put(System.FOLD_LOCK_BEHAVIOR, ANY_STRING_VALIDATOR);
         VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
         VALIDATORS.put(System.TEXT_AUTO_REPLACE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.TEXT_AUTO_CAPS, BOOLEAN_VALIDATOR);
@@ -219,7 +220,6 @@
         VALIDATORS.put(System.WIFI_STATIC_DNS1, LENIENT_IP_ADDRESS_VALIDATOR);
         VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR);
         VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(System.STAY_AWAKE_ON_FOLD, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 203efbf..c0f6231 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -98,7 +98,6 @@
                     Settings.System.VOLUME_VOICE, // deprecated since API 2?
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
                     Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
-                    Settings.System.DESKTOP_MODE, // developer setting for internal prototyping
                     Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.SCREEN_BRIGHTNESS_FLOAT,
@@ -658,7 +657,6 @@
                     Settings.Global.Wearable.COMPANION_BLE_ROLE,
                     Settings.Global.Wearable.COMPANION_NAME,
                     Settings.Global.Wearable.COMPANION_APP_NAME,
-                    Settings.Global.Wearable.USER_HFP_CLIENT_SETTING,
                     Settings.Global.Wearable.COMPANION_OS_VERSION,
                     Settings.Global.Wearable.ENABLE_ALL_LANGUAGES,
                     Settings.Global.Wearable.SETUP_LOCALE,
@@ -673,16 +671,12 @@
                     Settings.Global.Wearable.CLOCKWORK_LONG_PRESS_TO_ASSISTANT_ENABLED,
                     Settings.Global.Wearable.WET_MODE_ON,
                     Settings.Global.Wearable.COOLDOWN_MODE_ON,
-                    Settings.Global.Wearable.CHARGING_SOUNDS_ENABLED,
-                    Settings.Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED,
                     Settings.Global.Wearable.BEDTIME_MODE,
                     Settings.Global.Wearable.BEDTIME_HARD_MODE,
-                    Settings.Global.Wearable.RSB_WAKE_ENABLED,
                     Settings.Global.Wearable.LOCK_SCREEN_STATE,
                     Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_ENABLED,
                     Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_TYPE,
                     Settings.Global.Wearable.ACCESSIBILITY_VIBRATION_WATCH_SPEED,
-                    Settings.Global.Wearable.SCREENSHOT_ENABLED,
                     Settings.Global.Wearable.DISABLE_AOD_WHILE_PLUGGED,
                     Settings.Global.Wearable.NETWORK_LOCATION_OPT_IN,
                     Settings.Global.Wearable.CUSTOM_COLOR_FOREGROUND,
diff --git a/packages/SharedStorageBackup/Android.bp b/packages/SharedStorageBackup/Android.bp
index 21516fa..225b5b4 100644
--- a/packages/SharedStorageBackup/Android.bp
+++ b/packages/SharedStorageBackup/Android.bp
@@ -27,9 +27,6 @@
     name: "SharedStorageBackup",
     defaults: ["platform_app_defaults"],
     srcs: ["src/**/*.java"],
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
     platform_apis: true,
     certificate: "platform",
     privileged: true,
diff --git a/packages/SharedStorageBackup/proguard.flags b/packages/SharedStorageBackup/proguard.flags
deleted file mode 100644
index 6a66a47..0000000
--- a/packages/SharedStorageBackup/proguard.flags
+++ /dev/null
@@ -1,2 +0,0 @@
--keep class com.android.sharedstoragebackup.SharedStorageAgent
--keep class com.android.sharedstoragebackup.ObbBackupService
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 2077af8..bba79bb 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -132,20 +132,6 @@
     manifest: "AndroidManifest-res.xml",
 }
 
-aconfig_declarations {
-    name: "systemui_aconfig_flags",
-    package: "com.android.systemui.aconfig",
-    srcs: [
-        "src/com/android/systemui/aconfig/systemui.aconfig",
-        "src/com/android/systemui/accessibility/aconfig/accessibility.aconfig",
-    ],
-}
-
-java_aconfig_library {
-    name: "systemui_aconfig_flags_lib",
-    aconfig_declarations: "systemui_aconfig_flags",
-}
-
 android_library {
     name: "SystemUI-core",
     defaults: [
@@ -180,7 +166,7 @@
         "SystemUISharedLib",
         "SystemUI-statsd",
         "SettingsLib",
-        "systemui_aconfig_flags_lib",
+        "com_android_systemui_flags_lib",
         "androidx.core_core-ktx",
         "androidx.viewpager2_viewpager2",
         "androidx.legacy_legacy-support-v4",
@@ -251,6 +237,9 @@
         "tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/FakeAirplaneModeRepository.kt",
         "tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt",
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt",
+
+        /* Log fakes */
+        "tests/src/com/android/systemui/log/core/FakeLogBuffer.kt",
     ],
     path: "tests/src",
 }
@@ -326,6 +315,39 @@
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt",
         "tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt",
+
+        /* Bouncer UI tests */
+        "tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt",
+        "tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt",
+        "tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java",
+        "tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt",
+        "tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java",
+        "tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt",
+        "tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java",
+        "tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt",
+        "tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt",
+
+        /* Communal tests */
+        "tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt",
+        "tests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt",
+        "tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt",
+
+        /* Dream tests */
+        "tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java",
+        "tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java",
+        "tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java",
+        "tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java",
+        "tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java",
+        "tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java",
+        "tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java",
+        "tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt",
+        "tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt",
+        "tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java",
+        "tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java",
+        "tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java",
+        "tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java",
+        "tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java",
+        "tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java",
     ],
     path: "tests/src",
 }
@@ -358,7 +380,7 @@
         "SystemUICustomizationLib",
         "SystemUI-statsd",
         "SettingsLib",
-        "systemui_aconfig_flags_lib",
+        "com_android_systemui_flags_lib",
         "androidx.viewpager2_viewpager2",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
@@ -530,10 +552,12 @@
                 optimize: true,
                 shrink: true,
                 shrink_resources: true,
+                ignore_warnings: false,
                 proguard_compatibility: false,
             },
             conditions_default: {
                 optimize: {
+                    ignore_warnings: false,
                     proguard_compatibility: false,
                 },
             },
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6778d5a..b5b873c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -349,6 +349,9 @@
 
     <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
 
+    <!-- Listen to (dis-)connection of external displays and enable / disable them. -->
+    <uses-permission android:name="android.permission.MANAGE_DISPLAYS" />
+
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/aconfig/Android.bp b/packages/SystemUI/aconfig/Android.bp
new file mode 100644
index 0000000..c1390b2
--- /dev/null
+++ b/packages/SystemUI/aconfig/Android.bp
@@ -0,0 +1,13 @@
+aconfig_declarations {
+    name: "com_android_systemui_flags",
+    package: "com.android.systemui",
+    srcs: [
+        "systemui.aconfig",
+        "accessibility.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "com_android_systemui_flags_lib",
+    aconfig_declarations: "com_android_systemui_flags",
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
similarity index 83%
rename from packages/SystemUI/src/com/android/systemui/accessibility/aconfig/accessibility.aconfig
rename to packages/SystemUI/aconfig/accessibility.aconfig
index 91c5551..8841967 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -1,7 +1,8 @@
-package: "com.android.systemui.aconfig"
+package: "com.android.systemui"
+
 flag {
     name: "floating_menu_overlaps_nav_bars_flag"
     namespace: "accessibility"
     description: "Adjusts bounds to allow the floating menu to render on top of navigation bars."
     bug: "283768342"
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig
rename to packages/SystemUI/aconfig/systemui.aconfig
index 2d6e257..70832f5 100644
--- a/packages/SystemUI/src/com/android/systemui/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1,8 +1,8 @@
-package: "com.android.systemui.aconfig"
+package: "com.android.systemui"
 
 flag {
     name: "example_flag"
     namespace: "systemui"
     description: "An Example Flag"
     bug: "292511372"
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 8eb012d..6f53b42 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -68,5 +68,6 @@
     kotlincflags: ["-Xjvm-default=all"],
 
     // sdk_version must be specified, otherwise it compiles against private APIs.
+    min_sdk_version: "33",
     sdk_version: "current",
 }
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
index d9a45cd..2069ebd 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -19,18 +19,25 @@
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.DraggableState
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.draggable
 import androidx.compose.foundation.gestures.rememberDraggableState
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableFloatStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
+import com.android.compose.nestedscroll.PriorityPostNestedScrollConnection
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -70,23 +77,38 @@
     // the same as SwipeableV2Defaults.PositionalThreshold.
     val positionalThreshold = with(LocalDensity.current) { 56.dp.toPx() }
 
-    return draggable(
-        orientation = orientation,
-        enabled = enabled,
-        startDragImmediately = startDragImmediately,
-        onDragStarted = { onDragStarted(layoutImpl, transition, orientation) },
-        state =
-            rememberDraggableState { delta -> onDrag(layoutImpl, transition, orientation, delta) },
-        onDragStopped = { velocity ->
-            onDragStopped(
-                layoutImpl,
-                transition,
-                velocity,
-                velocityThreshold,
-                positionalThreshold,
-            )
-        },
-    )
+    val draggableState = rememberDraggableState { delta ->
+        onDrag(layoutImpl, transition, orientation, delta)
+    }
+
+    return nestedScroll(
+            connection =
+                rememberSwipeToSceneNestedScrollConnection(
+                    orientation = orientation,
+                    coroutineScope = rememberCoroutineScope(),
+                    draggableState = draggableState,
+                    transition = transition,
+                    layoutImpl = layoutImpl,
+                    velocityThreshold = velocityThreshold,
+                    positionalThreshold = positionalThreshold
+                ),
+        )
+        .draggable(
+            state = draggableState,
+            orientation = orientation,
+            enabled = enabled,
+            startDragImmediately = startDragImmediately,
+            onDragStarted = { onDragStarted(layoutImpl, transition, orientation) },
+            onDragStopped = { velocity ->
+                onDragStopped(
+                    layoutImpl = layoutImpl,
+                    transition = transition,
+                    velocity = velocity,
+                    velocityThreshold = velocityThreshold,
+                    positionalThreshold = positionalThreshold,
+                )
+            },
+        )
 }
 
 private class SwipeTransition(initialScene: Scene) : TransitionState.Transition {
@@ -235,35 +257,18 @@
     // twice in a row to accelerate the transition and go from A => B then B => C really fast.
     maybeHandleAcceleratedSwipe(transition, orientation)
 
-    val fromScene = transition._fromScene
-    val upOrLeft = fromScene.upOrLeft(orientation)
-    val downOrRight = fromScene.downOrRight(orientation)
     val offset = transition.dragOffset
+    val fromScene = transition._fromScene
 
     // Compute the target scene depending on the current offset.
-    val targetSceneKey: SceneKey
-    val signedDistance: Float
-    when {
-        offset < 0f && upOrLeft != null -> {
-            targetSceneKey = upOrLeft
-            signedDistance = -transition.absoluteDistance
-        }
-        offset > 0f && downOrRight != null -> {
-            targetSceneKey = downOrRight
-            signedDistance = transition.absoluteDistance
-        }
-        else -> {
-            targetSceneKey = fromScene.key
-            signedDistance = 0f
-        }
+    val target = fromScene.findTargetSceneAndDistance(orientation, offset, layoutImpl)
+
+    if (transition._toScene.key != target.sceneKey) {
+        transition._toScene = layoutImpl.scenes.getValue(target.sceneKey)
     }
 
-    if (transition._toScene.key != targetSceneKey) {
-        transition._toScene = layoutImpl.scenes.getValue(targetSceneKey)
-    }
-
-    if (transition._distance != signedDistance) {
-        transition._distance = signedDistance
+    if (transition._distance != target.distance) {
+        transition._distance = target.distance
     }
 }
 
@@ -299,12 +304,55 @@
     // using fromScene and dragOffset.
 }
 
+private data class TargetScene(
+    val sceneKey: SceneKey,
+    val distance: Float,
+)
+
+private fun Scene.findTargetSceneAndDistance(
+    orientation: Orientation,
+    directionOffset: Float,
+    layoutImpl: SceneTransitionLayoutImpl,
+): TargetScene {
+    val maxDistance =
+        when (orientation) {
+            Orientation.Horizontal -> layoutImpl.size.width
+            Orientation.Vertical -> layoutImpl.size.height
+        }.toFloat()
+
+    val upOrLeft = upOrLeft(orientation)
+    val downOrRight = downOrRight(orientation)
+
+    // Compute the target scene depending on the current offset.
+    return when {
+        directionOffset < 0f && upOrLeft != null -> {
+            TargetScene(
+                sceneKey = upOrLeft,
+                distance = -maxDistance,
+            )
+        }
+        directionOffset > 0f && downOrRight != null -> {
+            TargetScene(
+                sceneKey = downOrRight,
+                distance = maxDistance,
+            )
+        }
+        else -> {
+            TargetScene(
+                sceneKey = key,
+                distance = 0f,
+            )
+        }
+    }
+}
+
 private fun CoroutineScope.onDragStopped(
     layoutImpl: SceneTransitionLayoutImpl,
     transition: SwipeTransition,
     velocity: Float,
     velocityThreshold: Float,
     positionalThreshold: Float,
+    canChangeScene: Boolean = true,
 ) {
     // The state was changed since the drag started; don't do anything.
     if (layoutImpl.state.transitionState != transition) {
@@ -323,14 +371,15 @@
     val offset = transition.dragOffset
     val distance = transition.distance
     if (
-        shouldCommitSwipe(
-            offset,
-            distance,
-            velocity,
-            velocityThreshold,
-            positionalThreshold,
-            wasCommitted = transition._currentScene == transition._toScene,
-        )
+        canChangeScene &&
+            shouldCommitSwipe(
+                offset,
+                distance,
+                velocity,
+                velocityThreshold,
+                positionalThreshold,
+                wasCommitted = transition._currentScene == transition._toScene,
+            )
     ) {
         targetOffset = distance
         targetScene = transition._toScene
@@ -348,31 +397,13 @@
         layoutImpl.onChangeScene(targetScene.key)
     }
 
-    // Animate the offset.
-    transition.offsetAnimationJob = launch {
-        transition.offsetAnimatable.snapTo(offset)
-        transition.isAnimatingOffset = true
-
-        transition.offsetAnimatable.animateTo(
-            targetOffset,
-            // TODO(b/290184746): Make this spring spec configurable.
-            spring(
-                stiffness = Spring.StiffnessMediumLow,
-                visibilityThreshold = OffsetVisibilityThreshold
-            ),
-            initialVelocity = velocity,
-        )
-
-        // Now that the animation is done, the state should be idle. Note that if the state was
-        // changed since this animation started, some external code changed it and we shouldn't do
-        // anything here. Note also that this job will be cancelled in the case where the user
-        // intercepts this swipe.
-        if (layoutImpl.state.transitionState == transition) {
-            layoutImpl.state.transitionState = TransitionState.Idle(targetScene.key)
-        }
-
-        transition.offsetAnimationJob = null
-    }
+    animateOffset(
+        transition = transition,
+        layoutImpl = layoutImpl,
+        initialVelocity = velocity,
+        targetOffset = targetOffset,
+        targetScene = targetScene.key
+    )
 }
 
 /**
@@ -412,8 +443,216 @@
     }
 }
 
+private fun CoroutineScope.animateOffset(
+    transition: SwipeTransition,
+    layoutImpl: SceneTransitionLayoutImpl,
+    initialVelocity: Float,
+    targetOffset: Float,
+    targetScene: SceneKey,
+) {
+    transition.offsetAnimationJob = launch {
+        if (!transition.isAnimatingOffset) {
+            transition.offsetAnimatable.snapTo(transition.dragOffset)
+        }
+        transition.isAnimatingOffset = true
+
+        transition.offsetAnimatable.animateTo(
+            targetOffset,
+            // TODO(b/290184746): Make this spring spec configurable.
+            spring(
+                stiffness = Spring.StiffnessMediumLow,
+                visibilityThreshold = OffsetVisibilityThreshold
+            ),
+            initialVelocity = initialVelocity,
+        )
+
+        // Now that the animation is done, the state should be idle. Note that if the state was
+        // changed since this animation started, some external code changed it and we shouldn't do
+        // anything here. Note also that this job will be cancelled in the case where the user
+        // intercepts this swipe.
+        if (layoutImpl.state.transitionState == transition) {
+            layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
+        }
+
+        transition.offsetAnimationJob = null
+    }
+}
+
+private fun CoroutineScope.animateOverscroll(
+    layoutImpl: SceneTransitionLayoutImpl,
+    transition: SwipeTransition,
+    velocity: Velocity,
+    orientation: Orientation,
+): Velocity {
+    val velocityAmount =
+        when (orientation) {
+            Orientation.Vertical -> velocity.y
+            Orientation.Horizontal -> velocity.x
+        }
+
+    if (velocityAmount == 0f) {
+        // There is no remaining velocity
+        return Velocity.Zero
+    }
+
+    val fromScene = layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
+    val target = fromScene.findTargetSceneAndDistance(orientation, velocityAmount, layoutImpl)
+    val isValidTarget = target.distance != 0f && target.sceneKey != fromScene.key
+
+    if (!isValidTarget || layoutImpl.state.transitionState == transition) {
+        // We have not found a valid target or we are already in a transition
+        return Velocity.Zero
+    }
+
+    transition._currentScene = fromScene
+    transition._fromScene = fromScene
+    transition._toScene = layoutImpl.scene(target.sceneKey)
+    transition._distance = target.distance
+    transition.absoluteDistance = target.distance.absoluteValue
+    transition.dragOffset = 0f
+    transition.isAnimatingOffset = false
+    transition.offsetAnimationJob = null
+
+    layoutImpl.state.transitionState = transition
+
+    animateOffset(
+        transition = transition,
+        layoutImpl = layoutImpl,
+        initialVelocity = velocityAmount,
+        targetOffset = 0f,
+        targetScene = fromScene.key
+    )
+
+    // The animateOffset animation consumes any remaining velocity.
+    return velocity
+}
+
 /**
  * The number of pixels below which there won't be a visible difference in the transition and from
  * which the animation can stop.
  */
 private const val OffsetVisibilityThreshold = 0.5f
+
+@Composable
+private fun rememberSwipeToSceneNestedScrollConnection(
+    orientation: Orientation,
+    coroutineScope: CoroutineScope,
+    draggableState: DraggableState,
+    transition: SwipeTransition,
+    layoutImpl: SceneTransitionLayoutImpl,
+    velocityThreshold: Float,
+    positionalThreshold: Float,
+): PriorityPostNestedScrollConnection {
+    val density = LocalDensity.current
+    val scrollConnection =
+        remember(
+            orientation,
+            coroutineScope,
+            draggableState,
+            transition,
+            layoutImpl,
+            velocityThreshold,
+            positionalThreshold,
+            density,
+        ) {
+            fun Offset.toAmount() =
+                when (orientation) {
+                    Orientation.Horizontal -> x
+                    Orientation.Vertical -> y
+                }
+
+            fun Velocity.toAmount() =
+                when (orientation) {
+                    Orientation.Horizontal -> x
+                    Orientation.Vertical -> y
+                }
+
+            fun Float.toOffset() =
+                when (orientation) {
+                    Orientation.Horizontal -> Offset(x = this, y = 0f)
+                    Orientation.Vertical -> Offset(x = 0f, y = this)
+                }
+
+            // The next potential scene is calculated during the canStart
+            var nextScene: SceneKey? = null
+
+            // This is the scene on which we will have priority during the scroll gesture.
+            var priorityScene: SceneKey? = null
+
+            // If we performed a long gesture before entering priority mode, we would have to avoid
+            // moving on to the next scene.
+            var gestureStartedOnNestedChild = false
+
+            PriorityPostNestedScrollConnection(
+                canStart = { offsetAvailable, offsetBeforeStart ->
+                    val amount = offsetAvailable.toAmount()
+                    if (amount == 0f) return@PriorityPostNestedScrollConnection false
+
+                    gestureStartedOnNestedChild = offsetBeforeStart != Offset.Zero
+
+                    val fromScene = layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
+                    nextScene =
+                        when {
+                            amount < 0f -> fromScene.upOrLeft(orientation)
+                            amount > 0f -> fromScene.downOrRight(orientation)
+                            else -> null
+                        }
+
+                    nextScene != null
+                },
+                canContinueScroll = { priorityScene == transition._toScene.key },
+                onStart = {
+                    priorityScene = nextScene
+                    onDragStarted(layoutImpl, transition, orientation)
+                },
+                onScroll = { offsetAvailable ->
+                    val amount = offsetAvailable.toAmount()
+
+                    // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture
+                    // is initiated in a nested child.
+
+                    // Appends a new coroutine to attempt to drag by [amount] px. In this case we
+                    // are assuming that the [coroutineScope] is tied to the main thread and that
+                    // calls to [launch] are therefore queued.
+                    coroutineScope.launch { draggableState.drag { dragBy(amount) } }
+
+                    amount.toOffset()
+                },
+                onStop = { velocityAvailable ->
+                    priorityScene = null
+
+                    coroutineScope.onDragStopped(
+                        layoutImpl = layoutImpl,
+                        transition = transition,
+                        velocity = velocityAvailable.toAmount(),
+                        velocityThreshold = velocityThreshold,
+                        positionalThreshold = positionalThreshold,
+                        canChangeScene = !gestureStartedOnNestedChild
+                    )
+
+                    // The onDragStopped animation consumes any remaining velocity.
+                    velocityAvailable
+                },
+                onPostFling = { velocityAvailable ->
+                    // If there is any velocity left, we can try running an overscroll animation
+                    // between scenes.
+                    coroutineScope.animateOverscroll(
+                        layoutImpl = layoutImpl,
+                        transition = transition,
+                        velocity = velocityAvailable,
+                        orientation = orientation
+                    )
+                },
+            )
+        }
+    DisposableEffect(scrollConnection) {
+        onDispose {
+            coroutineScope.launch {
+                // This should ensure that the draggableState is in a consistent state and that it
+                // does not cause any unexpected behavior.
+                scrollConnection.reset()
+            }
+        }
+    }
+    return scrollConnection
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt b/packages/SystemUI/compose/core/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
new file mode 100644
index 0000000..cea8d9a
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnection.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.nestedscroll
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+
+/**
+ * A [NestedScrollConnection] that listens for all vertical scroll events and responds in the
+ * following way:
+ * - If you **scroll up**, it **first brings the [height]** back to the [minHeight] and then allows
+ *   scrolling of the children (usually the content).
+ * - If you **scroll down**, it **first allows scrolling of the children** (usually the content) and
+ *   then resets the [height] to [maxHeight].
+ *
+ * This behavior is useful for implementing a
+ * [Large top app bar](https://m3.material.io/components/top-app-bar/specs) effect or something
+ * similar.
+ *
+ * @sample com.android.compose.animation.scene.demo.Shade
+ */
+class LargeTopAppBarNestedScrollConnection(
+    private val height: () -> Float,
+    private val onChangeHeight: (Float) -> Unit,
+    private val minHeight: Float,
+    private val maxHeight: Float,
+) : NestedScrollConnection {
+
+    constructor(
+        height: () -> Float,
+        onHeightChanged: (Float) -> Unit,
+        heightRange: ClosedFloatingPointRange<Float>,
+    ) : this(
+        height = height,
+        onChangeHeight = onHeightChanged,
+        minHeight = heightRange.start,
+        maxHeight = heightRange.endInclusive,
+    )
+
+    /**
+     * When swiping up, the LargeTopAppBar will shrink (to [minHeight]) and the content will expand.
+     * Then, you can then scroll down the content.
+     */
+    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+        val y = available.y
+        val currentHeight = height()
+        if (y >= 0 || currentHeight <= minHeight) {
+            return Offset.Zero
+        }
+
+        val amountLeft = minHeight - currentHeight
+        val amountConsumed = y.coerceAtLeast(amountLeft)
+        onChangeHeight(currentHeight + amountConsumed)
+        return Offset(0f, amountConsumed)
+    }
+
+    /**
+     * When swiping down, the content will scroll up until it reaches the top. Then, the
+     * LargeTopAppBar will expand until it reaches its [maxHeight].
+     */
+    override fun onPostScroll(
+        consumed: Offset,
+        available: Offset,
+        source: NestedScrollSource
+    ): Offset {
+        val y = available.y
+        val currentHeight = height()
+        if (y <= 0 || currentHeight >= maxHeight) {
+            return Offset.Zero
+        }
+
+        val amountLeft = maxHeight - currentHeight
+        val amountConsumed = y.coerceAtMost(amountLeft)
+        onChangeHeight(currentHeight + amountConsumed)
+        return Offset(0f, amountConsumed)
+    }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnection.kt b/packages/SystemUI/compose/core/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnection.kt
new file mode 100644
index 0000000..793a9a5
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnection.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.nestedscroll
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.unit.Velocity
+
+/**
+ * This [NestedScrollConnection] waits for a child to scroll ([onPostScroll]), and then decides (via
+ * [canStart]) if it should take over scrolling. If it does, it will scroll before its children,
+ * until [canContinueScroll] allows it.
+ *
+ * Note: Call [reset] before destroying this object to make sure you always get a call to [onStop]
+ * after [onStart].
+ *
+ * @sample com.android.compose.animation.scene.rememberSwipeToSceneNestedScrollConnection
+ */
+class PriorityPostNestedScrollConnection(
+    private val canStart: (offsetAvailable: Offset, offsetBeforeStart: Offset) -> Boolean,
+    private val canContinueScroll: () -> Boolean,
+    private val onStart: () -> Unit,
+    private val onScroll: (offsetAvailable: Offset) -> Offset,
+    private val onStop: (velocityAvailable: Velocity) -> Velocity,
+    private val onPostFling: suspend (velocityAvailable: Velocity) -> Velocity,
+) : NestedScrollConnection {
+
+    /** In priority mode [onPreScroll] events are first consumed by the parent, via [onScroll]. */
+    private var isPriorityMode = false
+
+    private var offsetScrolledBeforePriorityMode = Offset.Zero
+
+    override fun onPostScroll(
+        consumed: Offset,
+        available: Offset,
+        source: NestedScrollSource,
+    ): Offset {
+        // The offset before the start takes into account the up and down movements, starting from
+        // the beginning or from the last fling gesture.
+        val offsetBeforeStart = offsetScrolledBeforePriorityMode - available
+
+        if (
+            isPriorityMode ||
+                source == NestedScrollSource.Fling ||
+                !canStart(available, offsetBeforeStart)
+        ) {
+            // The priority mode cannot start so we won't consume the available offset.
+            return Offset.Zero
+        }
+
+        // Step 1: It's our turn! We start capturing scroll events when one of our children has an
+        // available offset following a scroll event.
+        isPriorityMode = true
+
+        // Note: onStop will be called if we cannot continue to scroll (step 3a), or the finger is
+        // lifted (step 3b), or this object has been destroyed (step 3c).
+        onStart()
+
+        return onScroll(available)
+    }
+
+    override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
+        if (!isPriorityMode) {
+            if (source != NestedScrollSource.Fling) {
+                // We want to track the amount of offset consumed before entering priority mode
+                offsetScrolledBeforePriorityMode += available
+            }
+
+            return Offset.Zero
+        }
+
+        if (!canContinueScroll()) {
+            // Step 3a: We have lost priority and we no longer need to intercept scroll events.
+            onPriorityStop(velocity = Velocity.Zero)
+            return Offset.Zero
+        }
+
+        // Step 2: We have the priority and can consume the scroll events.
+        return onScroll(available)
+    }
+
+    override suspend fun onPreFling(available: Velocity): Velocity {
+        // Step 3b: The finger is lifted, we can stop intercepting scroll events and use the speed
+        // of the fling gesture.
+        return onPriorityStop(velocity = available)
+    }
+
+    override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
+        return onPostFling(available)
+    }
+
+    /** Method to call before destroying the object or to reset the initial state. */
+    fun reset() {
+        // Step 3c: To ensure that an onStop is always called for every onStart.
+        onPriorityStop(velocity = Velocity.Zero)
+    }
+
+    private fun onPriorityStop(velocity: Velocity): Velocity {
+
+        // We can restart tracking the consumed offsets from scratch.
+        offsetScrolledBeforePriorityMode = Offset.Zero
+
+        if (!isPriorityMode) {
+            return Velocity.Zero
+        }
+
+        isPriorityMode = false
+
+        return onStop(velocity)
+    }
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
new file mode 100644
index 0000000..03d231a
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/nestedscroll/LargeTopAppBarNestedScrollConnectionTest.kt
@@ -0,0 +1,145 @@
+/*
+ * 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.nestedscroll
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+class LargeTopAppBarNestedScrollConnectionTest(testCase: TestCase) {
+    val scrollSource = testCase.scrollSource
+
+    private var height = 0f
+
+    private fun buildScrollConnection(heightRange: ClosedFloatingPointRange<Float>) =
+        LargeTopAppBarNestedScrollConnection(
+            height = { height },
+            onHeightChanged = { height = it },
+            heightRange = heightRange,
+        )
+
+    @Test
+    fun onScrollUp_consumeHeightFirst() {
+        val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+        height = 1f
+
+        val offsetConsumed =
+            scrollConnection.onPreScroll(available = Offset(x = 0f, y = -1f), source = scrollSource)
+
+        // It can decrease by 1 the height
+        assertThat(offsetConsumed).isEqualTo(Offset(0f, -1f))
+        assertThat(height).isEqualTo(0f)
+    }
+
+    @Test
+    fun onScrollUp_consumeDownToMin() {
+        val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+        height = 0f
+
+        val offsetConsumed =
+            scrollConnection.onPreScroll(available = Offset(x = 0f, y = -1f), source = scrollSource)
+
+        // It should not change the height (already at min)
+        assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+        assertThat(height).isEqualTo(0f)
+    }
+
+    @Test
+    fun onScrollUp_ignorePostScroll() {
+        val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+        height = 1f
+
+        val offsetConsumed =
+            scrollConnection.onPostScroll(
+                consumed = Offset.Zero,
+                available = Offset(x = 0f, y = -1f),
+                source = scrollSource
+            )
+
+        // It should ignore all onPostScroll events
+        assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+        assertThat(height).isEqualTo(1f)
+    }
+
+    @Test
+    fun onScrollDown_allowConsumeContentFirst() {
+        val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+        height = 1f
+
+        val offsetConsumed =
+            scrollConnection.onPreScroll(available = Offset(x = 0f, y = 1f), source = scrollSource)
+
+        // It should ignore all onPreScroll events
+        assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+        assertThat(height).isEqualTo(1f)
+    }
+
+    @Test
+    fun onScrollDown_consumeHeightPostScroll() {
+        val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+        height = 1f
+
+        val offsetConsumed =
+            scrollConnection.onPostScroll(
+                consumed = Offset.Zero,
+                available = Offset(x = 0f, y = 1f),
+                source = scrollSource
+            )
+
+        // It can increase by 1 the height
+        assertThat(offsetConsumed).isEqualTo(Offset(0f, 1f))
+        assertThat(height).isEqualTo(2f)
+    }
+
+    @Test
+    fun onScrollDown_consumeUpToMax() {
+        val scrollConnection = buildScrollConnection(heightRange = 0f..2f)
+        height = 2f
+
+        val offsetConsumed =
+            scrollConnection.onPostScroll(
+                consumed = Offset.Zero,
+                available = Offset(x = 0f, y = 1f),
+                source = scrollSource
+            )
+
+        // It should not change the height (already at max)
+        assertThat(offsetConsumed).isEqualTo(Offset.Zero)
+        assertThat(height).isEqualTo(2f)
+    }
+
+    // NestedScroll Source is a value/inline class and must be wrapped in a parameterized test
+    // https://youtrack.jetbrains.com/issue/KT-35523/Parameterized-JUnit-tests-with-inline-classes-throw-IllegalArgumentException
+    data class TestCase(val scrollSource: NestedScrollSource) {
+        override fun toString() = scrollSource.toString()
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun data(): List<TestCase> =
+            listOf(
+                TestCase(NestedScrollSource.Drag),
+                TestCase(NestedScrollSource.Fling),
+                TestCase(NestedScrollSource.Wheel),
+            )
+    }
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnectionTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnectionTest.kt
new file mode 100644
index 0000000..8e2b77a
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/nestedscroll/PriorityPostNestedScrollConnectionTest.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.compose.nestedscroll
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.unit.Velocity
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PriorityPostNestedScrollConnectionTest {
+    private var canStart = false
+    private var canContinueScroll = false
+    private var isStarted = false
+    private var lastScroll: Offset? = null
+    private var returnOnScroll = Offset.Zero
+    private var lastStop: Velocity? = null
+    private var returnOnStop = Velocity.Zero
+    private var lastOnPostFling: Velocity? = null
+    private var returnOnPostFling = Velocity.Zero
+
+    private val scrollConnection =
+        PriorityPostNestedScrollConnection(
+            canStart = { _, _ -> canStart },
+            canContinueScroll = { canContinueScroll },
+            onStart = { isStarted = true },
+            onScroll = {
+                lastScroll = it
+                returnOnScroll
+            },
+            onStop = {
+                lastStop = it
+                returnOnStop
+            },
+            onPostFling = {
+                lastOnPostFling = it
+                returnOnPostFling
+            },
+        )
+
+    private val offset1 = Offset(1f, 1f)
+    private val offset2 = Offset(2f, 2f)
+    private val velocity1 = Velocity(1f, 1f)
+    private val velocity2 = Velocity(2f, 2f)
+
+    private fun startPriorityMode() {
+        canStart = true
+        scrollConnection.onPostScroll(
+            consumed = Offset.Zero,
+            available = Offset.Zero,
+            source = NestedScrollSource.Drag
+        )
+    }
+
+    @Test
+    fun step1_priorityModeShouldStartOnlyOnPostScroll() = runTest {
+        canStart = true
+
+        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPreFling(available = Velocity.Zero)
+        assertThat(isStarted).isEqualTo(false)
+
+        scrollConnection.onPostFling(consumed = Velocity.Zero, available = Velocity.Zero)
+        assertThat(isStarted).isEqualTo(false)
+
+        startPriorityMode()
+        assertThat(isStarted).isEqualTo(true)
+    }
+
+    @Test
+    fun step1_priorityModeShouldStartOnlyIfAllowed() {
+        scrollConnection.onPostScroll(
+            consumed = Offset.Zero,
+            available = Offset.Zero,
+            source = NestedScrollSource.Drag
+        )
+        assertThat(isStarted).isEqualTo(false)
+
+        startPriorityMode()
+        assertThat(isStarted).isEqualTo(true)
+    }
+
+    @Test
+    fun step1_onPriorityModeStarted_receiveAvailableOffset() {
+        canStart = true
+
+        scrollConnection.onPostScroll(
+            consumed = offset1,
+            available = offset2,
+            source = NestedScrollSource.Drag
+        )
+
+        assertThat(lastScroll).isEqualTo(offset2)
+    }
+
+    @Test
+    fun step2_onPriorityMode_shouldContinueIfAllowed() {
+        startPriorityMode()
+        canContinueScroll = true
+
+        scrollConnection.onPreScroll(available = offset1, source = NestedScrollSource.Drag)
+        assertThat(lastScroll).isEqualTo(offset1)
+
+        canContinueScroll = false
+        scrollConnection.onPreScroll(available = offset2, source = NestedScrollSource.Drag)
+        assertThat(lastScroll).isNotEqualTo(offset2)
+        assertThat(lastScroll).isEqualTo(offset1)
+    }
+
+    @Test
+    fun step3a_onPriorityMode_shouldStopIfCannotContinue() {
+        startPriorityMode()
+        canContinueScroll = false
+
+        scrollConnection.onPreScroll(available = Offset.Zero, source = NestedScrollSource.Drag)
+
+        assertThat(lastStop).isNotNull()
+    }
+
+    @Test
+    fun step3b_onPriorityMode_shouldStopOnFling() = runTest {
+        startPriorityMode()
+        canContinueScroll = true
+
+        scrollConnection.onPreFling(available = Velocity.Zero)
+
+        assertThat(lastStop).isNotNull()
+    }
+
+    @Test
+    fun step3c_onPriorityMode_shouldStopOnReset() {
+        startPriorityMode()
+        canContinueScroll = true
+
+        scrollConnection.reset()
+
+        assertThat(lastStop).isNotNull()
+    }
+
+    @Test
+    fun receive_onPostFling() = runTest {
+        scrollConnection.onPostFling(
+            consumed = velocity1,
+            available = velocity2,
+        )
+
+        assertThat(lastOnPostFling).isEqualTo(velocity2)
+    }
+}
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/BouncerSceneModule.kt
similarity index 72%
rename from tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
rename to packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/BouncerSceneModule.kt
index a7bd771..1a5e22b 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/BouncerSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.apkverity;
+package com.android.systemui.scene
 
-import android.app.Activity;
+import dagger.Module
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+@Module interface BouncerSceneModule
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
similarity index 72%
copy from tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
copy to packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
index a7bd771..5cc3b75d 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/GoneSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.apkverity;
+package com.android.systemui.scene
 
-import android.app.Activity;
+import dagger.Module
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+@Module interface GoneSceneModule
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
similarity index 72%
copy from tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
copy to packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
index a7bd771..725aef2 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.apkverity;
+package com.android.systemui.scene
 
-import android.app.Activity;
+import dagger.Module
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+@Module interface LockscreenSceneModule
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
similarity index 72%
copy from tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
copy to packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
index a7bd771..387b056 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.apkverity;
+package com.android.systemui.scene
 
-import android.app.Activity;
+import dagger.Module
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+@Module interface QuickSettingsSceneModule
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ShadeSceneModule.kt
similarity index 72%
copy from tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
copy to packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ShadeSceneModule.kt
index a7bd771..232c421 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ShadeSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.apkverity;
+package com.android.systemui.scene
 
-import android.app.Activity;
+import dagger.Module
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+@Module interface ShadeSceneModule
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt
new file mode 100644
index 0000000..ddc3d3a
--- /dev/null
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene
+
+import android.app.AlertDialog
+import android.content.Context
+import com.android.systemui.bouncer.ui.composable.BouncerScene
+import com.android.systemui.bouncer.ui.composable.BouncerSceneDialogFactory
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoSet
+
+@Module
+interface BouncerSceneModule {
+
+    @Binds @IntoSet fun bouncerScene(scene: BouncerScene): Scene
+
+    companion object {
+
+        @Provides
+        @SysUISingleton
+        fun bouncerSceneDialogFactory(@Application context: Context): BouncerSceneDialogFactory {
+            return object : BouncerSceneDialogFactory {
+                override fun invoke(): AlertDialog {
+                    return SystemUIDialog(context)
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/GoneSceneModule.kt
similarity index 69%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/GoneSceneModule.kt
index 24064b1..bc3fef1 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/GoneSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.ui.composable
+package com.android.systemui.scene
 
 import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.ui.composable.GoneScene
+import dagger.Binds
 import dagger.Module
-import dagger.multibindings.Multibinds
+import dagger.multibindings.IntoSet
 
 @Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+interface GoneSceneModule {
+
+    @Binds @IntoSet fun goneScene(scene: GoneScene): Scene
 }
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
new file mode 100644
index 0000000..4d53cca
--- /dev/null
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene
+
+import android.view.View
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.KeyguardViewConfigurator
+import com.android.systemui.keyguard.qualifiers.KeyguardRootView
+import com.android.systemui.keyguard.ui.composable.LockscreenScene
+import com.android.systemui.scene.shared.model.Scene
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoSet
+import javax.inject.Provider
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@Module
+interface LockscreenSceneModule {
+
+    @Binds @IntoSet fun lockscreenScene(scene: LockscreenScene): Scene
+
+    companion object {
+
+        @OptIn(ExperimentalCoroutinesApi::class)
+        @Provides
+        @SysUISingleton
+        @KeyguardRootView
+        fun viewProvider(
+            configurator: Provider<KeyguardViewConfigurator>,
+        ): () -> View {
+            return { configurator.get().getKeyguardRootView() }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
similarity index 66%
rename from packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
rename to packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
index 8da1803..ee1f525 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsSceneModule.kt
@@ -14,19 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.domain.startable
+package com.android.systemui.scene
 
-import com.android.systemui.CoreStartable
+import com.android.systemui.qs.ui.composable.QuickSettingsScene
+import com.android.systemui.scene.shared.model.Scene
 import dagger.Binds
 import dagger.Module
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
+import dagger.multibindings.IntoSet
 
 @Module
-interface SceneContainerStartableModule {
+interface QuickSettingsSceneModule {
 
-    @Binds
-    @IntoMap
-    @ClassKey(SceneContainerStartable::class)
-    fun bind(impl: SceneContainerStartable): CoreStartable
+    @Binds @IntoSet fun quickSettingsScene(scene: QuickSettingsScene): Scene
 }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ShadeSceneModule.kt
similarity index 68%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ShadeSceneModule.kt
index 24064b1..c655d6b 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ShadeSceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.ui.composable
+package com.android.systemui.scene
 
 import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.shade.ui.composable.ShadeScene
+import dagger.Binds
 import dagger.Module
-import dagger.multibindings.Multibinds
+import dagger.multibindings.IntoSet
 
 @Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+interface ShadeSceneModule {
+
+    @Binds @IntoSet fun shadeScene(scene: ShadeScene): Scene
 }
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
deleted file mode 100644
index 3e9b397..0000000
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.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.systemui.scene.ui.composable
-
-import android.app.AlertDialog
-import android.content.Context
-import com.android.systemui.bouncer.ui.composable.BouncerScene
-import com.android.systemui.bouncer.ui.composable.BouncerSceneDialogFactory
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.ui.composable.LockscreenScene
-import com.android.systemui.qs.ui.composable.QuickSettingsScene
-import com.android.systemui.scene.shared.model.Scene
-import com.android.systemui.shade.ui.composable.ShadeScene
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import dagger.Module
-import dagger.Provides
-
-@Module
-object SceneModule {
-    @Provides
-    fun scenes(
-        bouncer: BouncerScene,
-        gone: GoneScene,
-        lockScreen: LockscreenScene,
-        qs: QuickSettingsScene,
-        shade: ShadeScene,
-    ): Set<Scene> {
-        return setOf(
-            bouncer,
-            gone,
-            lockScreen,
-            qs,
-            shade,
-        )
-    }
-
-    @Provides
-    @SysUISingleton
-    fun bouncerSceneDialogFactory(@Application context: Context): BouncerSceneDialogFactory {
-        return object : BouncerSceneDialogFactory {
-            override fun invoke(): AlertDialog {
-                return SystemUIDialog(context)
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 7545ff4..8a8557a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -21,7 +21,6 @@
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.LocalTextStyle
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.TextField
@@ -45,7 +44,6 @@
 import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
 
 /** UI for the input part of a password-requiring version of the bouncer. */
-@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 internal fun PasswordBouncer(
     viewModel: PasswordBouncerViewModel,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
index 64227b8..03efbe0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt
@@ -21,6 +21,8 @@
 import androidx.compose.animation.core.AnimationVector1D
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.gestures.awaitEachGesture
+import androidx.compose.foundation.gestures.awaitFirstDown
 import androidx.compose.foundation.gestures.detectDragGestures
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
@@ -199,33 +201,39 @@
             .onSizeChanged { containerSize = it }
             .thenIf(isInputEnabled) {
                 Modifier.pointerInput(Unit) {
-                    detectDragGestures(
-                        onDragStart = { start ->
-                            inputPosition = start
-                            viewModel.onDragStart()
-                        },
-                        onDragEnd = {
-                            inputPosition = null
-                            if (isAnimationEnabled) {
-                                lineFadeOutAnimatables.values.forEach { animatable ->
-                                    // Launch using the longer-lived scope because we want these
-                                    // animations to proceed to completion even if the surrounding
-                                    // scope is canceled.
-                                    scope.launch { animatable.animateTo(1f) }
-                                }
-                            }
-                            viewModel.onDragEnd()
-                        },
-                    ) { change, _ ->
-                        inputPosition = change.position
-                        viewModel.onDrag(
-                            xPx = change.position.x,
-                            yPx = change.position.y,
-                            containerSizePx = containerSize.width,
-                            verticalOffsetPx = verticalOffset,
-                        )
+                        awaitEachGesture {
+                            awaitFirstDown()
+                            viewModel.onDown()
+                        }
                     }
-                }
+                    .pointerInput(Unit) {
+                        detectDragGestures(
+                            onDragStart = { start ->
+                                inputPosition = start
+                                viewModel.onDragStart()
+                            },
+                            onDragEnd = {
+                                inputPosition = null
+                                if (isAnimationEnabled) {
+                                    lineFadeOutAnimatables.values.forEach { animatable ->
+                                        // Launch using the longer-lived scope because we want these
+                                        // animations to proceed to completion even if the
+                                        // surrounding scope is canceled.
+                                        scope.launch { animatable.animateTo(1f) }
+                                    }
+                                }
+                                viewModel.onDragEnd()
+                            },
+                        ) { change, _ ->
+                            inputPosition = change.position
+                            viewModel.onDrag(
+                                xPx = change.position.x,
+                                yPx = change.position.y,
+                                containerSizePx = containerSize.width,
+                                verticalOffsetPx = verticalOffset,
+                            )
+                        }
+                    }
             }
     ) {
         if (isAnimationEnabled) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index ec6e5ed..e5c6977 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -24,6 +24,8 @@
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.awaitEachGesture
+import androidx.compose.foundation.gestures.awaitFirstDown
 import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -76,7 +78,13 @@
 
     Column(
         horizontalAlignment = Alignment.CenterHorizontally,
-        modifier = modifier,
+        modifier =
+            modifier.pointerInput(Unit) {
+                awaitEachGesture {
+                    awaitFirstDown()
+                    viewModel.onDown()
+                }
+            }
     ) {
         PinInputDisplay(viewModel)
         Spacer(Modifier.height(100.dp))
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
index 48f40e7..418df5c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/dialog/ui/composable/AlertDialogContent.kt
@@ -19,13 +19,11 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.defaultMinSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material3.LocalContentColor
@@ -35,9 +33,13 @@
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.Placeable
+import androidx.compose.ui.layout.layoutId
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
 import com.android.compose.theme.LocalAndroidColorScheme
+import kotlin.math.roundToInt
 
 /**
  * The content of an AlertDialog which can be used together with
@@ -99,28 +101,101 @@
         Spacer(Modifier.height(32.dp))
 
         // Buttons.
-        // TODO(b/283817398): If there is not enough space, the buttons should automatically stack
-        // as shown in go/sysui-dialog-styling.
         if (positiveButton != null || negativeButton != null || neutralButton != null) {
-            Row(Modifier.fillMaxWidth()) {
-                if (neutralButton != null) {
-                    neutralButton()
-                    Spacer(Modifier.width(8.dp))
-                }
+            AlertDialogButtons(
+                positiveButton = positiveButton,
+                negativeButton = negativeButton,
+                neutralButton = neutralButton,
+            )
+        }
+    }
+}
 
-                Spacer(Modifier.weight(1f))
+@Composable
+private fun AlertDialogButtons(
+    positiveButton: (@Composable () -> Unit)?,
+    negativeButton: (@Composable () -> Unit)?,
+    neutralButton: (@Composable () -> Unit)?,
+    modifier: Modifier = Modifier,
+) {
+    Layout(
+        content = {
+            positiveButton?.let { Box(Modifier.layoutId("positive")) { it() } }
+            negativeButton?.let { Box(Modifier.layoutId("negative")) { it() } }
+            neutralButton?.let { Box(Modifier.layoutId("neutral")) { it() } }
+        },
+        modifier,
+    ) { measurables, constraints ->
+        check(constraints.hasBoundedWidth) {
+            "AlertDialogButtons should not be composed in an horizontally scrollable layout"
+        }
+        val maxWidth = constraints.maxWidth
 
-                if (negativeButton != null) {
-                    negativeButton()
-                }
+        // Measure the buttons.
+        var positive: Placeable? = null
+        var negative: Placeable? = null
+        var neutral: Placeable? = null
+        for (i in measurables.indices) {
+            val measurable = measurables[i]
+            when (val layoutId = measurable.layoutId) {
+                "positive" -> positive = measurable.measure(constraints)
+                "negative" -> negative = measurable.measure(constraints)
+                "neutral" -> neutral = measurable.measure(constraints)
+                else -> error("Unexpected layoutId=$layoutId")
+            }
+        }
 
-                if (positiveButton != null) {
-                    if (negativeButton != null) {
-                        Spacer(Modifier.width(8.dp))
+        fun Placeable?.width() = this?.width ?: 0
+        fun Placeable?.height() = this?.height ?: 0
+
+        // The min horizontal spacing between buttons.
+        val horizontalSpacing = 8.dp.toPx()
+        val totalHorizontalSpacing = (measurables.size - 1) * horizontalSpacing
+        val requiredWidth =
+            positive.width() + negative.width() + neutral.width() + totalHorizontalSpacing
+
+        if (requiredWidth <= maxWidth) {
+            // Stack horizontally: [neutral][flexSpace][negative][positive].
+            val height = maxOf(positive.height(), negative.height(), neutral.height())
+            layout(maxWidth, height) {
+                positive?.let { it.placeRelative(maxWidth - it.width, 0) }
+
+                negative?.let { negative ->
+                    if (positive == null) {
+                        negative.placeRelative(maxWidth - negative.width, 0)
+                    } else {
+                        negative.placeRelative(
+                            maxWidth -
+                                negative.width -
+                                positive.width -
+                                horizontalSpacing.roundToInt(),
+                            0
+                        )
                     }
-
-                    positiveButton()
                 }
+
+                neutral?.placeRelative(0, 0)
+            }
+        } else {
+            // Stack vertically, aligned on the right (in LTR layouts):
+            //   [positive]
+            //   [negative]
+            //    [neutral]
+            //
+            // TODO(b/283817398): Introduce a ResponsiveDialogButtons composable to create buttons
+            // that have different styles when stacked horizontally, as shown in
+            // go/sysui-dialog-styling.
+            val height = positive.height() + negative.height() + neutral.height()
+            layout(maxWidth, height) {
+                var y = 0
+                fun Placeable.place() {
+                    placeRelative(maxWidth - width, y)
+                    y += this.height
+                }
+
+                positive?.place()
+                negative?.place()
+                neutral?.place()
             }
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index 0a100ba..463253b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -14,20 +14,33 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
+@file:OptIn(ExperimentalCoroutinesApi::class, ExperimentalFoundationApi::class)
 
 package com.android.systemui.keyguard.ui.composable
 
 import android.view.View
 import android.view.ViewGroup
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.gestures.awaitEachGesture
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.graphics.toComposeRect
+import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.view.isVisible
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.qualifiers.KeyguardRootView
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
 import com.android.systemui.scene.shared.model.Direction
 import com.android.systemui.scene.shared.model.SceneKey
@@ -67,8 +80,8 @@
         modifier: Modifier,
     ) {
         LockscreenScene(
-            viewModel = viewModel,
             viewProvider = viewProvider,
+            longPressViewModel = viewModel.longPress,
             modifier = modifier,
         )
     }
@@ -85,23 +98,68 @@
 
 @Composable
 private fun LockscreenScene(
-    viewModel: LockscreenSceneViewModel,
     viewProvider: () -> View,
+    longPressViewModel: KeyguardLongPressViewModel,
     modifier: Modifier = Modifier,
 ) {
-    AndroidView(
-        factory = { _ ->
-            val keyguardRootView = viewProvider()
-            // Remove the KeyguardRootView from any parent it might already have in legacy code just
-            // in case (a view can't have two parents).
-            (keyguardRootView.parent as? ViewGroup)?.removeView(keyguardRootView)
-            keyguardRootView
-        },
-        update = { keyguardRootView ->
-            keyguardRootView.requireViewById<View>(R.id.lock_icon_view).setOnClickListener {
-                viewModel.onLockButtonClicked()
-            }
-        },
+    fun findSettingsMenu(): View {
+        return viewProvider().requireViewById(R.id.keyguard_settings_button)
+    }
+
+    Box(
         modifier = modifier,
+    ) {
+        LongPressSurface(
+            viewModel = longPressViewModel,
+            isSettingsMenuVisible = { findSettingsMenu().isVisible },
+            settingsMenuBounds = {
+                val bounds = android.graphics.Rect()
+                findSettingsMenu().getHitRect(bounds)
+                bounds.toComposeRect()
+            },
+            modifier = Modifier.fillMaxSize(),
+        )
+
+        AndroidView(
+            factory = { _ ->
+                val keyguardRootView = viewProvider()
+                // Remove the KeyguardRootView from any parent it might already have in legacy code
+                // just in case (a view can't have two parents).
+                (keyguardRootView.parent as? ViewGroup)?.removeView(keyguardRootView)
+                keyguardRootView
+            },
+            modifier = Modifier.fillMaxSize(),
+        )
+    }
+}
+
+@Composable
+private fun LongPressSurface(
+    viewModel: KeyguardLongPressViewModel,
+    isSettingsMenuVisible: () -> Boolean,
+    settingsMenuBounds: () -> Rect,
+    modifier: Modifier = Modifier,
+) {
+    val isEnabled: Boolean by viewModel.isLongPressHandlingEnabled.collectAsState(initial = false)
+
+    Box(
+        modifier =
+            modifier
+                .combinedClickable(
+                    enabled = isEnabled,
+                    onLongClick = viewModel::onLongPress,
+                    onClick = {},
+                )
+                .pointerInput(Unit) {
+                    awaitEachGesture {
+                        val pointerInputChange = awaitFirstDown()
+                        if (
+                            isSettingsMenuVisible() &&
+                                !settingsMenuBounds().contains(pointerInputChange.position)
+                        ) {
+                            viewModel.onTouchedOutside()
+                        }
+                    }
+                },
     )
 }
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 13acde2..4822200 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
@@ -137,6 +137,7 @@
             )
         }
 
+    val horizontalPadding = dimensionResource(R.dimen.qs_content_horizontal_padding)
     Row(
         modifier
             .fillMaxWidth()
@@ -150,6 +151,8 @@
             .padding(
                 top = dimensionResource(R.dimen.qs_footer_actions_top_padding),
                 bottom = dimensionResource(R.dimen.qs_footer_actions_bottom_padding),
+                start = horizontalPadding,
+                end = horizontalPadding,
             )
             .layout { measurable, constraints ->
                 // All buttons have a 4dp padding to increase their touch size. To be consistent
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index e5cd439..7ac3901 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -16,15 +16,19 @@
 
 package com.android.systemui.qs.ui.composable
 
+import android.view.ViewGroup
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.footer.ui.compose.QuickSettings
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
@@ -33,6 +37,10 @@
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.shared.model.UserAction
 import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -44,6 +52,9 @@
 @Inject
 constructor(
     private val viewModel: QuickSettingsSceneViewModel,
+    private val tintedIconManagerFactory: TintedIconManager.Factory,
+    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
+    private val statusBarIconController: StatusBarIconController,
 ) : ComposableScene {
     override val key = SceneKey.QuickSettings
 
@@ -61,6 +72,9 @@
     ) {
         QuickSettingsScene(
             viewModel = viewModel,
+            createTintedIconManager = tintedIconManagerFactory::create,
+            createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
+            statusBarIconController = statusBarIconController,
             modifier = modifier,
         )
     }
@@ -69,16 +83,27 @@
 @Composable
 private fun SceneScope.QuickSettingsScene(
     viewModel: QuickSettingsSceneViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
     modifier: Modifier = Modifier,
 ) {
     // TODO(b/280887232): implement the real UI.
-
-    Box(
-        modifier
-            .fillMaxSize()
-            .clickable(onClick = { viewModel.onContentClicked() })
-            .padding(horizontal = 16.dp, vertical = 48.dp)
+    Column(
+        horizontalAlignment = Alignment.CenterHorizontally,
+        modifier =
+            modifier
+                .fillMaxSize()
+                .clickable(onClick = { viewModel.onContentClicked() })
+                .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
     ) {
-        QuickSettings(modifier = Modifier.fillMaxHeight())
+        ExpandedShadeHeader(
+            viewModel = viewModel.shadeHeaderViewModel,
+            createTintedIconManager = createTintedIconManager,
+            createBatteryMeterViewController = createBatteryMeterViewController,
+            statusBarIconController = statusBarIconController,
+        )
+        Spacer(modifier = Modifier.height(16.dp))
+        QuickSettings()
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 774c409..40b0b4a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -17,11 +17,7 @@
 package com.android.systemui.scene.ui.composable
 
 import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.dagger.SysUISingleton
@@ -54,17 +50,6 @@
     override fun SceneScope.Content(
         modifier: Modifier,
     ) {
-        /*
-         * TODO(b/279501596): once we start testing with the real Content Dynamics Framework,
-         *  replace this with an error to make sure it doesn't get rendered.
-         */
-        Box(modifier = modifier) {
-            Column(
-                horizontalAlignment = Alignment.CenterHorizontally,
-                modifier = Modifier.align(Alignment.Center)
-            ) {
-                Text("Gone", style = MaterialTheme.typography.headlineMedium)
-            }
-        }
+        Box(modifier = modifier)
     }
 }
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 c865070..019287d 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
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalComposeUiApi::class)
+
 package com.android.systemui.scene.ui.composable
 
 import androidx.compose.foundation.layout.fillMaxSize
@@ -22,7 +24,11 @@
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.motionEventSpy
+import androidx.compose.ui.input.pointer.pointerInput
 import com.android.compose.animation.scene.Back
 import com.android.compose.animation.scene.ObservableTransitionState as SceneTransitionObservableTransitionState
 import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey
@@ -56,6 +62,7 @@
  *   must have entries in this map.
  * @param modifier A modifier.
  */
+@OptIn(ExperimentalComposeUiApi::class)
 @Composable
 fun SceneContainer(
     viewModel: SceneContainerViewModel,
@@ -79,7 +86,18 @@
         onChangeScene = viewModel::onSceneChanged,
         transitions = SceneContainerTransitions,
         state = state,
-        modifier = modifier.fillMaxSize(),
+        modifier =
+            modifier
+                .fillMaxSize()
+                .motionEventSpy { event -> viewModel.onMotionEvent(event) }
+                .pointerInput(Unit) {
+                    awaitPointerEventScope {
+                        while (true) {
+                            awaitPointerEvent(PointerEventPass.Final)
+                            viewModel.onMotionEventComplete()
+                        }
+                    }
+                }
     ) {
         sceneByKey.forEach { (sceneKey, composableScene) ->
             scene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index 21a10b1..be85bee 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -5,10 +5,18 @@
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.footer.ui.compose.QuickSettings
+import com.android.systemui.shade.ui.composable.ShadeHeader
 
 fun TransitionBuilder.shadeToQuickSettingsTransition() {
     spec = tween(durationMillis = 500)
 
     translate(Notifications.Elements.Notifications, Edge.Bottom)
     timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
+
+    translate(ShadeHeader.Elements.CollapsedContent, y = ShadeHeader.Dimensions.CollapsedHeight)
+    translate(ShadeHeader.Elements.ExpandedContent, y = (-ShadeHeader.Dimensions.ExpandedHeight))
+
+    fractionRange(end = .14f) { fade(ShadeHeader.Elements.CollapsedContent) }
+
+    fractionRange(start = .58f) { fade(ShadeHeader.Elements.ExpandedContent) }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
new file mode 100644
index 0000000..272e507
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.shade.ui.composable
+
+import android.view.ContextThemeWrapper
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.TransformOrigin
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ValueKey
+import com.android.compose.animation.scene.animateSharedFloatAsState
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.phone.StatusIconContainer
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.statusbar.policy.Clock
+
+object ShadeHeader {
+    object Elements {
+        val FormatPlaceholder = ElementKey("ShadeHeaderFormatPlaceholder")
+        val ExpandedContent = ElementKey("ShadeHeaderExpandedContent")
+        val CollapsedContent = ElementKey("ShadeHeaderCollapsedContent")
+    }
+
+    object Keys {
+        val transitionProgress = ValueKey("ShadeHeaderTransitionProgress")
+    }
+
+    object Dimensions {
+        val CollapsedHeight = 48.dp
+        val ExpandedHeight = 120.dp
+    }
+}
+
+@Composable
+fun SceneScope.CollapsedShadeHeader(
+    viewModel: ShadeHeaderViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
+    modifier: Modifier = Modifier,
+) {
+    // TODO(b/298153892): Remove this once animateSharedFloatAsState.element can be null.
+    Spacer(Modifier.element(ShadeHeader.Elements.FormatPlaceholder))
+    val formatProgress =
+        animateSharedFloatAsState(
+            0.0f,
+            ShadeHeader.Keys.transitionProgress,
+            ShadeHeader.Elements.FormatPlaceholder
+        )
+    val useExpandedFormat by
+        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }
+
+    Row(
+        modifier =
+            modifier
+                .element(ShadeHeader.Elements.CollapsedContent)
+                .fillMaxWidth()
+                .defaultMinSize(minHeight = ShadeHeader.Dimensions.CollapsedHeight),
+    ) {
+        AndroidView(
+            factory = { context ->
+                Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
+            },
+            modifier = Modifier.align(Alignment.CenterVertically),
+        )
+        Spacer(modifier = Modifier.width(5.dp))
+        VariableDayDate(
+            viewModel = viewModel,
+            modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically),
+        )
+        Spacer(modifier = Modifier.weight(1f))
+        SystemIconContainer {
+            StatusIcons(
+                viewModel = viewModel,
+                createTintedIconManager = createTintedIconManager,
+                statusBarIconController = statusBarIconController,
+                useExpandedFormat = useExpandedFormat,
+                modifier = Modifier.align(Alignment.CenterVertically).padding(end = 6.dp),
+            )
+            BatteryIcon(
+                createBatteryMeterViewController = createBatteryMeterViewController,
+                useExpandedFormat = useExpandedFormat,
+                modifier = Modifier.align(Alignment.CenterVertically),
+            )
+        }
+    }
+}
+
+@Composable
+fun SceneScope.ExpandedShadeHeader(
+    viewModel: ShadeHeaderViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
+    modifier: Modifier = Modifier,
+) {
+    // TODO(b/298153892): Remove this once animateSharedFloatAsState.element can be null.
+    Spacer(Modifier.element(ShadeHeader.Elements.FormatPlaceholder))
+    val formatProgress =
+        animateSharedFloatAsState(
+            1.0f,
+            ShadeHeader.Keys.transitionProgress,
+            ShadeHeader.Elements.FormatPlaceholder
+        )
+    val useExpandedFormat by
+        remember(formatProgress) { derivedStateOf { formatProgress.value > 0.5f } }
+
+    Column(
+        verticalArrangement = Arrangement.Bottom,
+        modifier =
+            modifier
+                .element(ShadeHeader.Elements.ExpandedContent)
+                .fillMaxWidth()
+                .defaultMinSize(minHeight = ShadeHeader.Dimensions.ExpandedHeight)
+    ) {
+        Row {
+            AndroidView(
+                factory = { context ->
+                    Clock(ContextThemeWrapper(context, R.style.TextAppearance_QS_Status), null)
+                },
+                modifier =
+                    Modifier.align(Alignment.CenterVertically)
+                        // use graphicsLayer instead of Modifier.scale to anchor transform to
+                        // top left corner
+                        .graphicsLayer(
+                            scaleX = 2.57f,
+                            scaleY = 2.57f,
+                            transformOrigin = TransformOrigin(0f, 0.5f)
+                        ),
+            )
+            Spacer(modifier = Modifier.weight(1f))
+            ShadeCarrierGroup(
+                viewModel = viewModel,
+                modifier = Modifier.align(Alignment.CenterVertically),
+            )
+        }
+        Spacer(modifier = Modifier.width(5.dp))
+        Row {
+            VariableDayDate(
+                viewModel = viewModel,
+                modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically),
+            )
+            Spacer(modifier = Modifier.weight(1f))
+            SystemIconContainer {
+                StatusIcons(
+                    viewModel = viewModel,
+                    createTintedIconManager = createTintedIconManager,
+                    statusBarIconController = statusBarIconController,
+                    useExpandedFormat = useExpandedFormat,
+                    modifier = Modifier.align(Alignment.CenterVertically).padding(end = 6.dp),
+                )
+                BatteryIcon(
+                    useExpandedFormat = useExpandedFormat,
+                    createBatteryMeterViewController = createBatteryMeterViewController,
+                    modifier = Modifier.align(Alignment.CenterVertically),
+                )
+            }
+        }
+    }
+}
+
+@Composable
+private fun BatteryIcon(
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    useExpandedFormat: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    AndroidView(
+        factory = { context ->
+            val batteryIcon = BatteryMeterView(context, null)
+            batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ON)
+
+            val batteryMaterViewController =
+                createBatteryMeterViewController(batteryIcon, StatusBarLocation.QS)
+            batteryMaterViewController.init()
+            batteryMaterViewController.ignoreTunerUpdates()
+
+            batteryIcon
+        },
+        update = { batteryIcon ->
+            // TODO(b/298525212): use MODE_ESTIMATE in collapsed view when the screen
+            //  has no center cutout. See [QsBatteryModeController.getBatteryMode]
+            batteryIcon.setPercentShowMode(
+                if (useExpandedFormat) {
+                    BatteryMeterView.MODE_ESTIMATE
+                } else {
+                    BatteryMeterView.MODE_ON
+                }
+            )
+        },
+        modifier = modifier,
+    )
+}
+
+@Composable
+private fun ShadeCarrierGroup(
+    viewModel: ShadeHeaderViewModel,
+    modifier: Modifier = Modifier,
+) {
+    Row(modifier = modifier) {
+        val subIds by viewModel.mobileSubIds.collectAsState()
+
+        for (subId in subIds) {
+            Spacer(modifier = Modifier.width(5.dp))
+            AndroidView(
+                factory = { context ->
+                    ModernShadeCarrierGroupMobileView.constructAndBind(
+                        context = context,
+                        logger = viewModel.mobileIconsViewModel.logger,
+                        slot = "mobile_carrier_shade_group",
+                        viewModel =
+                            (viewModel.mobileIconsViewModel.viewModelForSub(
+                                subId,
+                                StatusBarLocation.SHADE_CARRIER_GROUP
+                            ) as ShadeCarrierGroupMobileIconViewModel),
+                    )
+                },
+            )
+        }
+    }
+}
+
+@Composable
+private fun StatusIcons(
+    viewModel: ShadeHeaderViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    statusBarIconController: StatusBarIconController,
+    useExpandedFormat: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    val carrierIconSlots =
+        listOf(stringResource(id = com.android.internal.R.string.status_bar_mobile))
+    val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
+    val isTransitioning by viewModel.isTransitioning.collectAsState()
+
+    AndroidView(
+        factory = { context ->
+            val iconContainer = StatusIconContainer(context, null)
+            val iconManager = createTintedIconManager(iconContainer, StatusBarLocation.QS)
+            iconManager.setTint(
+                Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+            )
+            statusBarIconController.addIconGroup(iconManager)
+
+            iconContainer
+        },
+        update = { iconContainer ->
+            iconContainer.setQsExpansionTransitioning(isTransitioning)
+            if (isSingleCarrier || !useExpandedFormat) {
+                iconContainer.removeIgnoredSlots(carrierIconSlots)
+            } else {
+                iconContainer.addIgnoredSlots(carrierIconSlots)
+            }
+        },
+        modifier = modifier,
+    )
+}
+
+@Composable
+private fun SystemIconContainer(
+    modifier: Modifier = Modifier,
+    content: @Composable RowScope.() -> Unit
+) {
+    // TODO(b/298524053): add hover state for this container
+    Row(
+        modifier = modifier.height(ShadeHeader.Dimensions.CollapsedHeight),
+        content = content,
+    )
+}
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 f985aa2..b105637 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
@@ -16,9 +16,9 @@
 
 package com.android.systemui.shade.ui.composable
 
+import android.view.ViewGroup
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
@@ -33,6 +33,7 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.notifications.ui.composable.Notifications
@@ -43,6 +44,9 @@
 import com.android.systemui.scene.shared.model.UserAction
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.SharingStarted
@@ -77,6 +81,9 @@
 constructor(
     @Application private val applicationScope: CoroutineScope,
     private val viewModel: ShadeSceneViewModel,
+    private val tintedIconManagerFactory: TintedIconManager.Factory,
+    private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
+    private val statusBarIconController: StatusBarIconController,
 ) : ComposableScene {
     override val key = SceneKey.Shade
 
@@ -92,7 +99,14 @@
     @Composable
     override fun SceneScope.Content(
         modifier: Modifier,
-    ) = ShadeScene(viewModel, modifier)
+    ) =
+        ShadeScene(
+            viewModel = viewModel,
+            createTintedIconManager = tintedIconManagerFactory::create,
+            createBatteryMeterViewController = batteryMeterViewControllerFactory::create,
+            statusBarIconController = statusBarIconController,
+            modifier = modifier,
+        )
 
     private fun destinationScenes(
         up: SceneKey,
@@ -107,6 +121,9 @@
 @Composable
 private fun SceneScope.ShadeScene(
     viewModel: ShadeSceneViewModel,
+    createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
+    createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController,
+    statusBarIconController: StatusBarIconController,
     modifier: Modifier = Modifier,
 ) {
     Box(modifier.element(Shade.Elements.Scrim)) {
@@ -116,16 +133,22 @@
                     .fillMaxSize()
                     .background(MaterialTheme.colorScheme.scrim, shape = Shade.Shapes.Scrim)
         )
-
         Column(
             horizontalAlignment = Alignment.CenterHorizontally,
-            verticalArrangement = Arrangement.spacedBy(16.dp),
             modifier =
                 Modifier.fillMaxSize()
                     .clickable(onClick = { viewModel.onContentClicked() })
-                    .padding(horizontal = 16.dp, vertical = 48.dp)
+                    .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
         ) {
+            CollapsedShadeHeader(
+                viewModel = viewModel.shadeHeaderViewModel,
+                createTintedIconManager = createTintedIconManager,
+                createBatteryMeterViewController = createBatteryMeterViewController,
+                statusBarIconController = statusBarIconController,
+            )
+            Spacer(modifier = Modifier.height(16.dp))
             QuickSettings(modifier = Modifier.height(160.dp))
+            Spacer(modifier = Modifier.height(16.dp))
             Notifications(modifier = Modifier.weight(1f))
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
new file mode 100644
index 0000000..799dbd6
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt
@@ -0,0 +1,64 @@
+package com.android.systemui.shade.ui.composable
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+
+@Composable
+fun VariableDayDate(
+    viewModel: ShadeHeaderViewModel,
+    modifier: Modifier = Modifier,
+) {
+    val longerText = viewModel.longerDateText.collectAsState()
+    val shorterText = viewModel.shorterDateText.collectAsState()
+
+    Layout(
+        contents =
+            listOf(
+                {
+                    Text(
+                        text = longerText.value,
+                        style = MaterialTheme.typography.titleSmall,
+                        color = MaterialTheme.colorScheme.onBackground,
+                        maxLines = 1,
+                    )
+                },
+                {
+                    Text(
+                        text = shorterText.value,
+                        style = MaterialTheme.typography.titleSmall,
+                        color = MaterialTheme.colorScheme.onBackground,
+                        maxLines = 1,
+                    )
+                },
+            ),
+        modifier = modifier,
+    ) { measureables, constraints ->
+        check(measureables.size == 2)
+        check(measureables[0].size == 1)
+        check(measureables[1].size == 1)
+
+        val longerMeasurable = measureables[0][0]
+        val shorterMeasurable = measureables[1][0]
+
+        val longerPlaceable = longerMeasurable.measure(constraints)
+        val shorterPlaceable = shorterMeasurable.measure(constraints)
+
+        // If width < maxWidth (and not <=), we can assume that the text fits.
+        val placeable =
+            when {
+                longerPlaceable.width < constraints.maxWidth &&
+                    longerPlaceable.height <= constraints.maxHeight -> longerPlaceable
+                shorterPlaceable.width < constraints.maxWidth &&
+                    shorterPlaceable.height <= constraints.maxHeight -> shorterPlaceable
+                else -> null
+            }
+
+        layout(placeable?.width ?: 0, placeable?.height ?: 0) { placeable?.placeRelative(0, 0) }
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 966e183..054f9ec 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -68,11 +68,11 @@
 private fun <TKey : Any, TVal : Any> ConcurrentHashMap<TKey, TVal>.concurrentGetOrPut(
     key: TKey,
     value: TVal,
-    onNew: () -> Unit
+    onNew: (TVal) -> Unit
 ): TVal {
     val result = this.putIfAbsent(key, value)
     if (result == null) {
-        onNew()
+        onNew(value)
     }
     return result ?: value
 }
@@ -148,6 +148,8 @@
             override fun onPluginAttached(
                 manager: PluginLifecycleManager<ClockProviderPlugin>
             ): Boolean {
+                manager.isDebug = true
+
                 if (keepAllLoaded) {
                     // Always load new plugins if requested
                     return true
@@ -177,15 +179,22 @@
                     val info =
                         availableClocks.concurrentGetOrPut(id, ClockInfo(metadata, null, manager)) {
                             isClockListChanged = true
-                            onConnected(id)
+                            onConnected(it)
                         }
 
                     if (manager != info.manager) {
                         logger.tryLog(
                             TAG,
                             LogLevel.ERROR,
-                            { str1 = id },
-                            { "Clock Id conflict on known attach: $str1 is double registered" }
+                            {
+                                str1 = id
+                                str2 = info.manager.toString()
+                                str3 = manager.toString()
+                            },
+                            {
+                                "Clock Id conflict on attach: " +
+                                    "$str1 is double registered by $str2 and $str3"
+                            }
                         )
                         continue
                     }
@@ -217,22 +226,29 @@
                     val info =
                         availableClocks.concurrentGetOrPut(id, ClockInfo(clock, plugin, manager)) {
                             isClockListChanged = true
-                            onConnected(id)
+                            onConnected(it)
                         }
 
                     if (manager != info.manager) {
                         logger.tryLog(
                             TAG,
                             LogLevel.ERROR,
-                            { str1 = id },
-                            { "Clock Id conflict on load: $str1 is double registered" }
+                            {
+                                str1 = id
+                                str2 = info.manager.toString()
+                                str3 = manager.toString()
+                            },
+                            {
+                                "Clock Id conflict on load: " +
+                                    "$str1 is double registered by $str2 and $str3"
+                            }
                         )
                         manager.unloadPlugin()
                         continue
                     }
 
                     info.provider = plugin
-                    onLoaded(id)
+                    onLoaded(info)
                 }
 
                 if (isClockListChanged) {
@@ -252,26 +268,33 @@
                         logger.tryLog(
                             TAG,
                             LogLevel.ERROR,
-                            { str1 = id },
-                            { "Clock Id conflict on unload: $str1 is double registered" }
+                            {
+                                str1 = id
+                                str2 = info?.manager.toString()
+                                str3 = manager.toString()
+                            },
+                            {
+                                "Clock Id conflict on unload: " +
+                                    "$str1 is double registered by $str2 and $str3"
+                            }
                         )
                         continue
                     }
                     info.provider = null
-                    onUnloaded(id)
+                    onUnloaded(info)
                 }
 
                 verifyLoadedProviders()
             }
 
             override fun onPluginDetached(manager: PluginLifecycleManager<ClockProviderPlugin>) {
-                val removed = mutableListOf<ClockId>()
+                val removed = mutableListOf<ClockInfo>()
                 availableClocks.entries.removeAll {
                     if (it.value.manager != manager) {
                         return@removeAll false
                     }
 
-                    removed.add(it.key)
+                    removed.add(it.value)
                     return@removeAll true
                 }
 
@@ -493,6 +516,12 @@
 
         scope.launch(bgDispatcher) {
             if (keepAllLoaded) {
+                logger.tryLog(
+                    TAG,
+                    LogLevel.INFO,
+                    {},
+                    { "verifyLoadedProviders: keepAllLoaded=true" }
+                )
                 // Enforce that all plugins are loaded if requested
                 for ((_, info) in availableClocks) {
                     info.manager?.loadPlugin()
@@ -503,6 +532,12 @@
 
             val currentClock = availableClocks[currentClockId]
             if (currentClock == null) {
+                logger.tryLog(
+                    TAG,
+                    LogLevel.INFO,
+                    {},
+                    { "verifyLoadedProviders: currentClock=null" }
+                )
                 // Current Clock missing, load no plugins and use default
                 for ((_, info) in availableClocks) {
                     info.manager?.unloadPlugin()
@@ -511,12 +546,13 @@
                 return@launch
             }
 
+            logger.tryLog(TAG, LogLevel.INFO, {}, { "verifyLoadedProviders: load currentClock" })
             val currentManager = currentClock.manager
             currentManager?.loadPlugin()
 
             for ((_, info) in availableClocks) {
                 val manager = info.manager
-                if (manager != null && manager.isLoaded && currentManager != manager) {
+                if (manager != null && currentManager != manager) {
                     manager.unloadPlugin()
                 }
             }
@@ -524,57 +560,68 @@
         }
     }
 
-    private fun onConnected(clockId: ClockId) {
-        logger.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Connected $str1" })
-        if (currentClockId == clockId) {
-            logger.tryLog(
-                TAG,
-                LogLevel.INFO,
-                { str1 = clockId },
-                { "Current clock ($str1) was connected" }
-            )
-        }
+    private fun onConnected(info: ClockInfo) {
+        val isCurrent = currentClockId == info.metadata.clockId
+        logger.tryLog(
+            TAG,
+            if (isCurrent) LogLevel.INFO else LogLevel.DEBUG,
+            {
+                str1 = info.metadata.clockId
+                str2 = info.manager.toString()
+                bool1 = isCurrent
+            },
+            { "Connected $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
+        )
     }
 
-    private fun onLoaded(clockId: ClockId) {
-        logger.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Loaded $str1" })
+    private fun onLoaded(info: ClockInfo) {
+        val isCurrent = currentClockId == info.metadata.clockId
+        logger.tryLog(
+            TAG,
+            if (isCurrent) LogLevel.INFO else LogLevel.DEBUG,
+            {
+                str1 = info.metadata.clockId
+                str2 = info.manager.toString()
+                bool1 = isCurrent
+            },
+            { "Loaded $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
+        )
 
-        if (currentClockId == clockId) {
-            logger.tryLog(
-                TAG,
-                LogLevel.INFO,
-                { str1 = clockId },
-                { "Current clock ($str1) was loaded" }
-            )
+        if (isCurrent) {
             triggerOnCurrentClockChanged()
         }
     }
 
-    private fun onUnloaded(clockId: ClockId) {
-        logger.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Unloaded $str1" })
+    private fun onUnloaded(info: ClockInfo) {
+        val isCurrent = currentClockId == info.metadata.clockId
+        logger.tryLog(
+            TAG,
+            if (isCurrent) LogLevel.WARNING else LogLevel.DEBUG,
+            {
+                str1 = info.metadata.clockId
+                str2 = info.manager.toString()
+                bool1 = isCurrent
+            },
+            { "Unloaded $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
+        )
 
-        if (currentClockId == clockId) {
-            logger.tryLog(
-                TAG,
-                LogLevel.WARNING,
-                { str1 = clockId },
-                { "Current clock ($str1) was unloaded" }
-            )
+        if (isCurrent) {
             triggerOnCurrentClockChanged()
         }
     }
 
-    private fun onDisconnected(clockId: ClockId) {
-        logger.tryLog(TAG, LogLevel.DEBUG, { str1 = clockId }, { "Disconnected $str1" })
-
-        if (currentClockId == clockId) {
-            logger.tryLog(
-                TAG,
-                LogLevel.WARNING,
-                { str1 = clockId },
-                { "Current clock ($str1) was disconnected" }
-            )
-        }
+    private fun onDisconnected(info: ClockInfo) {
+        val isCurrent = currentClockId == info.metadata.clockId
+        logger.tryLog(
+            TAG,
+            if (isCurrent) LogLevel.INFO else LogLevel.DEBUG,
+            {
+                str1 = info.metadata.clockId
+                str2 = info.manager.toString()
+                bool1 = isCurrent
+            },
+            { "Disconnected $str1 @$str2" + if (bool1) " (Current Clock)" else "" }
+        )
     }
 
     fun getClocks(): List<ClockMetadata> {
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
index 56c3f93..3e5e8a0 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java
@@ -33,6 +33,12 @@
     /** Returns the currently loaded plugin instance (if plugin is loaded) */
     T getPlugin();
 
+    /** Returns true if the lifecycle manager should log debug messages */
+    boolean getIsDebug();
+
+    /** Sets whether or not hte lifecycle manager should log debug messages */
+    void setIsDebug(boolean debug);
+
     /** returns true if the plugin is currently loaded */
     default boolean isLoaded() {
         return getPlugin() != null;
diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags
index 3194815..75de943 100644
--- a/packages/SystemUI/proguard_common.flags
+++ b/packages/SystemUI/proguard_common.flags
@@ -70,9 +70,6 @@
 -keep class com.android.systemui.log.core.** {
     *;
 }
--keep class com.android.systemui.fragments.FragmentService$FragmentCreator {
-    *;
-}
 -keep class androidx.core.app.CoreComponentFactory
 
 # Keep the wm shell lib
diff --git a/packages/SystemUI/res-keyguard/layout-land/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
deleted file mode 100644
index cd7ab98..0000000
--- a/packages/SystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-**
-** Copyright 2023, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <include layout="@layout/keyguard_pin_view_landscape" />
-
-</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout-sw600dp-land/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout-sw600dp-land/keyguard_pin_view.xml
deleted file mode 100644
index 80cc8c0..0000000
--- a/packages/SystemUI/res-keyguard/layout-sw600dp-land/keyguard_pin_view.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-**
-** Copyright 2023, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <include layout="@layout/keyguard_pin_view_portrait" />
-
-</FrameLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 29e14c5..f3cd9e4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 **
-** Copyright 2012, The Android Open Source Project
+** Copyright 2023, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License")
 ** you may not use this file except in compliance with the License.
@@ -16,10 +16,203 @@
 ** limitations under the License.
 */
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pin_view"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="vertical"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width">
 
-    <include layout="@layout/keyguard_pin_view_portrait" />
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
-</FrameLayout>
+    <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" />
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/pin_container"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_marginBottom="8dp"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layout_weight="1"
+        android:layoutDirection="ltr"
+        android:orientation="vertical">
+
+        <!-- Set this to be just above key1. It would be better to introduce a barrier above
+             key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
+             drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
+             case, the Flow should ensure that key1/2/3 all have the same top, so this should be
+             fine. -->
+        <com.android.keyguard.AlphaOptimizedRelativeLayout
+            android:id="@+id/row0"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:layout_constraintTop_toTopOf="parent"
+            androidprv:layout_constraintEnd_toEndOf="parent"
+            androidprv:layout_constraintStart_toStartOf="parent"
+            androidprv:layout_constraintBottom_toTopOf="@id/key1"
+            androidprv:layout_constraintVertical_bias="0.5">
+
+            <com.android.keyguard.PasswordTextView
+                android:id="@+id/pinEntry"
+                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_pin_area"
+                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
+        </com.android.keyguard.AlphaOptimizedRelativeLayout>
+
+        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
+             updated in KeyguardPINView to reduce the height of the PIN pad. -->
+        <androidx.constraintlayout.widget.Guideline
+            android:id="@+id/pin_pad_top_guideline"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            androidprv:layout_constraintGuide_percent="0"
+            android:orientation="horizontal" />
+
+        <com.android.keyguard.KeyguardPinFlowView
+            android:id="@+id/flow1"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:orientation="horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+
+            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="1.0"
+            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
+            androidprv:flow_verticalStyle="packed"
+
+            androidprv:flow_wrapMode="aligned"
+            androidprv:layout_constraintBottom_toBottomOf="parent"
+            androidprv:layout_constraintEnd_toEndOf="parent"
+            androidprv:layout_constraintStart_toStartOf="parent"
+            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+
+        <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/pinEntry" />
+
+        <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/pinEntry" />
+
+        <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.NumPadKey
+            android:id="@+id/key0"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:accessibilityTraversalBefore="@id/key_enter"
+            androidprv:digit="0"
+            androidprv:textView="@+id/pinEntry" />
+
+        <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" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <include layout="@layout/keyguard_eca"
+        android:id="@+id/keyguard_selector_fade_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginTop="@dimen/keyguard_eca_top_margin"
+        android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
+        android:gravity="center_horizontal"/>
+
+</com.android.keyguard.KeyguardPINView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_landscape.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_landscape.xml
deleted file mode 100644
index e00742d..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_landscape.xml
+++ /dev/null
@@ -1,231 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-**
-** Copyright 2023, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/keyguard_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" />
-
-        <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/row0"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintVertical_chainStyle="packed" />
-
-        <!-- Set this to be just above key1. It would be better to introduce a barrier above
-         key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
-         drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
-         case, the Flow should ensure that key1/2/3 all have the same top, so this should be
-         fine. -->
-        <com.android.keyguard.AlphaOptimizedRelativeLayout
-            android:id="@+id/row0"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintBottom_toTopOf="@+id/keyguard_selector_fade_container"
-            androidprv:layout_constraintTop_toBottomOf="@+id/bouncer_message_view"
-            tools:layout_editor_absoluteX="-16dp">
-
-            <com.android.keyguard.PasswordTextView
-                android:id="@+id/pinEntry"
-                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_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/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">
-
-        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
-        updated in KeyguardPINView to reduce the height of the PIN pad. -->
-        <androidx.constraintlayout.widget.Guideline
-            android:id="@+id/pin_pad_top_guideline"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            androidprv:layout_constraintGuide_percent="0" />
-
-        <com.android.keyguard.KeyguardPinFlowView
-            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_constraintBottom_toBottomOf="parent"
-            androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent"
-            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-</com.android.keyguard.KeyguardPINView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml
deleted file mode 100644
index f3cd9e4..0000000
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view_portrait.xml
+++ /dev/null
@@ -1,218 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2023, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License")
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/keyguard_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="vertical"
-    androidprv:layout_maxWidth="@dimen/keyguard_security_width">
-
-    <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" />
-
-    <androidx.constraintlayout.widget.ConstraintLayout
-        android:id="@+id/pin_container"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_marginBottom="8dp"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:layout_weight="1"
-        android:layoutDirection="ltr"
-        android:orientation="vertical">
-
-        <!-- Set this to be just above key1. It would be better to introduce a barrier above
-             key1/key2/key3, then place this View above that. Sadly, that doesn't work (the Barrier
-             drops to the bottom of the page, and key1/2/3 all shoot up to the top-left). In any
-             case, the Flow should ensure that key1/2/3 all have the same top, so this should be
-             fine. -->
-        <com.android.keyguard.AlphaOptimizedRelativeLayout
-            android:id="@+id/row0"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingBottom="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:layout_constraintTop_toTopOf="parent"
-            androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent"
-            androidprv:layout_constraintBottom_toTopOf="@id/key1"
-            androidprv:layout_constraintVertical_bias="0.5">
-
-            <com.android.keyguard.PasswordTextView
-                android:id="@+id/pinEntry"
-                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_pin_area"
-                androidprv:scaledTextSize="@integer/scaled_password_text_size" />
-        </com.android.keyguard.AlphaOptimizedRelativeLayout>
-
-        <!-- Guideline used to place the top row of keys relative to the screen height. This will be
-             updated in KeyguardPINView to reduce the height of the PIN pad. -->
-        <androidx.constraintlayout.widget.Guideline
-            android:id="@+id/pin_pad_top_guideline"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            androidprv:layout_constraintGuide_percent="0"
-            android:orientation="horizontal" />
-
-        <com.android.keyguard.KeyguardPinFlowView
-            android:id="@+id/flow1"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:orientation="horizontal"
-            android:clipChildren="false"
-            android:clipToPadding="false"
-
-            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="1.0"
-            androidprv:flow_verticalGap="@dimen/num_pad_entry_row_margin_bottom"
-            androidprv:flow_verticalStyle="packed"
-
-            androidprv:flow_wrapMode="aligned"
-            androidprv:layout_constraintBottom_toBottomOf="parent"
-            androidprv:layout_constraintEnd_toEndOf="parent"
-            androidprv:layout_constraintStart_toStartOf="parent"
-            androidprv:layout_constraintTop_toBottomOf="@id/pin_pad_top_guideline" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-
-        <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/pinEntry" />
-
-        <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/pinEntry" />
-
-        <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.NumPadKey
-            android:id="@+id/key0"
-            android:layout_width="0dp"
-            android:layout_height="0dp"
-            android:accessibilityTraversalBefore="@id/key_enter"
-            androidprv:digit="0"
-            androidprv:textView="@+id/pinEntry" />
-
-        <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" />
-    </androidx.constraintlayout.widget.ConstraintLayout>
-
-    <include layout="@layout/keyguard_eca"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:layout_marginTop="@dimen/keyguard_eca_top_margin"
-        android:layout_marginBottom="@dimen/keyguard_eca_bottom_margin"
-        android:gravity="center_horizontal"/>
-
-</com.android.keyguard.KeyguardPINView>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 027166f..c7c863b 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -118,7 +118,7 @@
     <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheden er blevet låst af administratoren"</string>
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheden blev låst manuelt"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke genkendt"</string>
-    <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Aktivér kameraadgang i Indstillinger for at bruge ansigtslås"</string>
+    <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Aktivér kameraadgang i Indstillinger for at bruge ansigtsoplåsning"</string>
     <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Angiv pinkoden til SIM-kortet. Du har # forsøg tilbage, før du skal kontakte dit mobilselskab for at låse din enhed op.}one{Angiv pinkoden til SIM-kortet. Du har # forsøg tilbage.}other{Angiv pinkoden til SIM-kortet. Du har # forsøg tilbage.}}"</string>
     <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har # forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.}one{SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har # forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.}other{SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har # forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
diff --git a/packages/SystemUI/res/layout/connected_display_dialog.xml b/packages/SystemUI/res/layout/connected_display_dialog.xml
new file mode 100644
index 0000000..569dd4c
--- /dev/null
+++ b/packages/SystemUI/res/layout/connected_display_dialog.xml
@@ -0,0 +1,69 @@
+<!--
+  Copyright (C) 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:paddingHorizontal="@dimen/dialog_side_padding"
+    android:paddingTop="@dimen/dialog_top_padding"
+    android:background="@*android:drawable/bottomsheet_background"
+    android:paddingBottom="@dimen/dialog_bottom_padding">
+
+    <ImageView
+        android:id="@+id/connected_display_dialog_icon"
+        android:layout_width="@dimen/screenrecord_logo_size"
+        android:layout_height="@dimen/screenrecord_logo_size"
+        android:importantForAccessibility="no"
+        android:src="@drawable/stat_sys_connected_display"
+        android:tint="?androidprv:attr/materialColorPrimary" />
+
+    <TextView
+        android:id="@+id/connected_display_dialog_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/screenrecord_title_margin_top"
+        android:gravity="center"
+        android:text="@string/connected_display_dialog_start_mirroring"
+        android:textAppearance="@style/TextAppearance.Dialog.Title" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/screenrecord_buttons_margin_top"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/cancel"
+            style="@style/Widget.Dialog.Button.BorderButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/cancel" />
+
+        <Space
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1" />
+
+        <Button
+            android:id="@+id/enable_display"
+            style="@style/Widget.Dialog.Button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/enable_display" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 909048e..b00908f 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -47,7 +47,7 @@
                 android:layout_height="48dp"
                 android:layout_marginTop="12dp"
                 android:layout_marginStart="16dp"
-                app:layout_constraintVertical_bias="0.0"
+                app:layout_constraintHorizontal_bias="0.0"
                 app:layout_constraintHorizontal_chainStyle="spread_inside"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toTopOf="parent"
@@ -65,7 +65,6 @@
                 android:layout_height="48dp"
                 android:layout_marginTop="12dp"
                 android:layout_marginEnd="16dp"
-                app:layout_constraintVertical_bias="1.0"
                 app:layout_constraintEnd_toEndOf="parent"
                 app:layout_constraintTop_toTopOf="parent"
                 app:layout_constraintStart_toEndOf="@id/manage_text"
diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml
deleted file mode 100644
index 3baae33..0000000
--- a/packages/SystemUI/res/layout/zen_mode_condition.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/Theme.SystemUI.QuickSettings"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:clipChildren="false"
-    android:layout_marginStart="1dp"
-    android:layout_marginEnd="0dp"
-    android:layout_weight="1"
-    android:gravity="center_vertical" >
-
-    <LinearLayout
-        android:id="@android:id/content"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dp"
-        android:gravity="center_vertical"
-        android:layout_centerVertical="true"
-        android:orientation="vertical"
-        android:layout_toEndOf="@android:id/checkbox"
-        android:layout_toStartOf="@android:id/button1">
-
-        <TextView
-            android:id="@android:id/text1"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:textAlignment="viewStart"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" />
-
-        <TextView
-            android:id="@android:id/text2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/zen_mode_condition_detail_item_interline_spacing"
-            android:ellipsize="end"
-            android:textAlignment="viewStart"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" />
-
-    </LinearLayout>
-
-    <ImageView
-        android:id="@android:id/button1"
-        style="@style/QSBorderlessButton"
-        android:background="@drawable/ripple_drawable_20dp"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_centerVertical="true"
-        android:scaleType="center"
-        android:layout_toStartOf="@android:id/button2"
-        android:contentDescription="@string/accessibility_quick_settings_less_time"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_qs_minus" />
-
-    <ImageView
-        android:id="@android:id/button2"
-        style="@style/QSBorderlessButton"
-        android:background="@drawable/ripple_drawable_20dp"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_alignParentEnd="true"
-        android:scaleType="center"
-        android:layout_centerVertical="true"
-        android:contentDescription="@string/accessibility_quick_settings_more_time"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_qs_plus" />
-
-</RelativeLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a1db50d..206a7ee 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"\'n Ander toestel het versoek om die stelseltaal te verander"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Verander taal"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Hou huidige taal"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Deel wi-fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Laat draadlose ontfouting op hierdie netwerk toe?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Netwerknaam (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adres (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Laat altyd toe op hierdie netwerk"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Verkeerde patroon"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Verkeerde wagwoord"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Te veel verkeerde pogings.\nProbeer oor <xliff:g id="NUMBER">%d</xliff:g> sekondes weer."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Noodgeval"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Probeer weer. Poging <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> van <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Jou data sal uitgevee word"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"As jy met jou volgende poging \'n verkeerde patroon invoer, sal hierdie toestel se data uitgevee word."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Wanneer jy deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Wanneer jy ’n app deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat in daardie app gewys of gespeel word. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Begin"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> het hierdie opsie gedeaktiveer"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Begin uitsaai?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Wanneer jy uitsaai, het Android toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Wanneer jy ’n app uitsaai, het Android toegang tot enigiets wat in daardie app gewys of gespeel word. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent-aandag is aan"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
     <string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoon en kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Onlangse appgebruik"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Sien onlangse toegang"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index bc7273d..09157f8 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"በሌላ መሣሪያ የተጠየቀ የስርዓት ቋንቋ ለውጥ"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ቋንቋ ቀይር"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"አሁን ያለውን ቋንቋ አቆይ"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fiን አጋራ"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"በዚህ አውታረ መረብ ላይ ገመድ-አልባ debugging ይፈቀድ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"የአውታረ መረብ ስም (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nየWi‑Fi አድራሻ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ሁልጊዜ በዚህ አውታረ መረብ ላይ ፍቀድ"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"የተሳሳተ ሥርዓተ ጥለት"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"የተሳሳተ የይለፍ ቃል"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ከልክ በላይ ብዙ የተሳሳቱ ሙከራዎች።\nበ<xliff:g id="NUMBER">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ድንገተኛ አደጋ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"እንደገና ይሞክሩ። ሙከራ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> ከ<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>።"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"የእርስዎ ውሂብ ይሰረዛል"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"በሚቀጥለው ሙከራ ላይ ትክክል ያልሆነ ሥርዓተ ጥለት ካስገቡ የዚህ መሣሪያ ውሂብ ይሰረዛል።"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"እርስዎ ሲያጋሩ፣ ሲቀርጹ ወይም cast ሲያደርጉ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በማያ ገጽዎ ላይ ለሚታይ ወይም በመሣሪያዎ ላይ ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"አንድን መተግበሪያ ሲያጋሩ፣ ሲቀርጹ ወይም cast ሲያደርጉ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በዚያ መተግበሪያ ላይ ለሚታይ ወይም ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ጀምር"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ይህን አማራጭ አሰናክሏል"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"cast ማድረግ ይጀምር?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"እርስዎ cast በሚያደርጉበት ጊዜ Android በማያ ገጽዎ ላይ ለሚታይ ወይም በመሣሪያዎ ላይ ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"አንድን መተግበሪያ cast ሲያደርጉ Android በዚያ መተግበሪያ ላይ ለሚታይ ወይም ለሚጫወት ማንኛውም ነገር መዳረሻ አለው። ስለዚህ እንደ ይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"የረዳት ትኩረት በርቷል"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string>
     <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ማይክሮፎን እና ካሜራ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"የቅርብ ጊዜ የመተግበሪያ አጠቃቀም"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"የቅርብ ጊዜ መዳረሻን አሳይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 7b8f23a..31b7cbe 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"طلب جهاز آخر تغيير لغة النظام."</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"تغيير اللغة"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"الإبقاء على اللغة الحالية"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"‏مشاركة اتصال Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء اللاسلكي\" على هذه الشبكة؟"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"‏اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi‏ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"السماح باستخدام هذه الميزة على هذه الشبكة دائمًا"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"النقش غير صحيح."</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"كلمة مرور غير صحيحة"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"تم إجراء عدد كبير جدًا من المحاولات غير الصحيحة.\nأعد المحاولة خلال <xliff:g id="NUMBER">%d</xliff:g> ثانية."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"الطوارئ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"يُرجى إعادة المحاولة. المحاولة <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> من <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"سيتم حذف بياناتك"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"عند إدخال نقش غير صحيح في المحاولة التالية، سيتم حذف بيانات هذا الجهاز."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"أثناء المشاركة أو التسجيل أو البثّ، يمكن لتطبيق \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" الوصول إلى كل المحتوى المعروض على شاشتك أو الذي يتم تشغيله على جهاز، لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"أثناء مشاركة محتوى تطبيق أو تسجيله أو بثّه، يمكن لتطبيق \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله في ذلك التطبيق، لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"بدء"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"تم إيقاف هذا الخيار من خلال تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"هل تريد بدء البثّ؟"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"‏أثناء البثّ، يمكن لنظام Android الوصول إلى كل المحتوى المعروض على شاشتك أو الذي يتم تشغيله على جهازك، لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"‏أثناء بثّ محتوى تطبيق، يمكن لنظام Android الوصول إلى كل المحتوى المعروض أو الذي يتم تشغيله في ذلك التطبيق، لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"‏ميزة لفت انتباه \"مساعد Google\" مفعّلة."</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string>
     <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"الميكروفون والكاميرا"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"آخر استخدام في التطبيقات"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"عرض آخر استخدام في التطبيقات"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 9b3be3c..732d19d 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"অন্য এটা ডিভাইচে ছিষ্টেমৰ ভাষা সলনি কৰাৰ অনুৰোধ কৰিছে"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ভাষা সলনি কৰক"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"বৰ্তমানৰ ভাষাটো ৰাখক"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ৱাই-ফাই শ্বেয়াৰ কৰক"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"এই নেটৱৰ্কত ৱায়াৰলেচ ডি\'বাগিংৰ অনুমতি দিবনে?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"নেটৱৰ্কৰ নাম (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nৱাই-ফাইৰ ঠিকনা (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"এই নেটৱৰ্কত সদায় অনুমতি দিয়ক"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ভুল আৰ্হি"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ভুল পাছৱৰ্ড"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"বহুসংখ্যক ভুল প্ৰয়াস।\n<xliff:g id="NUMBER">%d</xliff:g>ছেকেণ্ডত পুনৰ চেষ্টা কৰক।"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"জৰুৰীকালীন"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"আকৌ চেষ্টা কৰক। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> টাৰ প্ৰয়াসৰ ভিতৰত <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> টা প্ৰয়াস।"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"আপোনাৰ ডেটা মচি পেলোৱা হ’ব"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"আপুনি পৰৱৰ্তী প্ৰয়াসত এটা ভুল আৰ্হি দিলে, এই ডিভাইচটোৰ ডেটা মচি পেলোৱা হ’ব।"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"আপুনি শ্বেয়াৰ কৰা, ৰেকৰ্ড কৰা অথবা কাষ্ট কৰাৰ সময়ত, আপোনাৰ স্ক্ৰীনখনত দৃশ্যমান হোৱা যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"আপুনি শ্বেয়াৰ কৰা, ৰেকৰ্ড কৰা অথবা কাষ্ট কৰাৰ সময়ত, সেইটো এপত দৃশ্যমান যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"আৰম্ভ কৰক"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ এই বিকল্পটো অক্ষম কৰিছে"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"কাষ্ট কৰিবলৈ আৰম্ভ কৰিবনে?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"আপুনি কাষ্ট কৰাৰ সময়ত, আপোনাৰ স্ক্ৰীনখনত দৃশ্যমান যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ Androidৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"আপুনি এটা এপ্ কাষ্ট কৰাৰ সময়ত সেইটো এপত দৃশ্যমান হোৱা যিকোনো বস্তু অথবা আপোনাৰ ডিভাইচত প্লে’ কৰা যিকোনো সমললৈ Androidৰ এক্সেছ থাকে। গতিকে, পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistantএ আপোনাৰ কথা শুনি আছে"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string>
     <string name="install_app" msgid="5066668100199613936">"এপ্‌টো ইনষ্টল কৰক"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"মাইক্ৰ’ফ’ন আৰু কেমেৰা"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"শেহতীয়া এপৰ ব্যৱহাৰ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"শেহতীয়া এক্সেছ চাওক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index af63640..080f450 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Sistem dilinin dəyişdirilməsi başqa cihaz tərəfindən tələb olunur"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Dili dəyişin"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Cari dili saxlayın"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi-ı paylaşın"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu şəbəkədə WiFi sazlamasına icazə verilsin?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Şəbəkə Adı (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Ünvanı (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu şəbəkədə həmişə icazə verilsin"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Yanlış model"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Yanlış parol"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Həddindən çox yanlış cəhd.\n<xliff:g id="NUMBER">%d</xliff:g> saniyəyə yenidən cəhd edin."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Fövqəladə hal"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Yenidən cəhd edin. Cəhd: <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Data silinəcək"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Növbəti cəhddə yanlış model daxil etsəniz, bu cihazın datası silinəcək."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Paylaşım, qeydəalma və ya yayım zamanı <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ekranda görünən, yaxud cihazda oxudulan məlumatlara giriş edə bilir. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Tətbiq paylaşdıqda, qeydə aldıqda və ya yayımladıqda <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> həmin tətbiqdə göstərilən, yaxud oxudulan məlumatlara giriş edə bilir. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Başlayın"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> bu seçimi deaktiv edib"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Yayım başladılsın?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Yayım zamanı Android-in ekranda görünən, yaxud cihazda oxudulan məlumatlara girişi olur. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Tətbiq yayımladıqda Android-in həmin tətbiqdə göstərilən və ya oxudulan məlumatlara girişi olur. Parol, ödəniş detalları, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent aktivdir"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string>
     <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon və kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Son tətbiq istifadəsi"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Son girişə baxın"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 94c5265..b524c34 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Drugi uređaj je zatražio promenu jezika sistema"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Promeni jezik"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zadrži aktuelni jezik"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Deli WiFi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Želite da dozvolite bežično otklanjanje grešaka na ovoj mreži?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi adresa (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Uvek dozvoli na ovoj mreži"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Pogrešan šablon"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Pogrešna lozinka"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Previše netačnih pokušaja.\n Probajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Hitan slučaj"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Probajte ponovo. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. pokušaj od <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Podaci će se izbrisati"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ako unesete netačan šablon pri sledećem pokušaju, izbrisaćemo podatke sa ovog uređaja."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kada delite, snimate ili prebacujete, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup kompletnom sadržaju koji je vidljiv na ekranu ili se pušta na uređaju. Zato budite pažljivi sa lozinkama, informacijama o plaćanju, porukama, slikama i audio i video snimcima."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kada delite, snimate ili prebacujete aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup kompletnom sadržaju koji je vidljiv ili se pušta u toj aplikaciji. Zato budite pažljivi sa lozinkama, informacijama o plaćanju, porukama, slikama i audio i video snimcima."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Pokreni"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućila ovu opciju"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Želite da započnete prebacivanje?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kada prebacujete, Android ima pristup kompletnom sadržaju koji je vidljiv na ekranu ili se pušta na uređaju. Zato budite pažljivi sa lozinkama, informacijama o plaćanju, porukama, slikama i audio i video snimcima."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kada prebacujete aplikaciju, Android ima pristup kompletnom sadržaju koji je vidljiv ili se pušta u toj aplikaciji. Zato budite pažljivi sa lozinkama, informacijama o plaćanju, porukama, slikama i audio i video snimcima."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Pomoćnik je u aktivnom stanju"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string>
     <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavno koristila aplikacija"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Prikaži nedavni pristup"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index e271408..dd8199e 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Іншая прылада запытала змяненне мовы сістэмы"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Змяніць мову"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Захаваць бягучую мову"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Абагуліць Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Дазволіць адладку па Wi-Fi у гэтай сетцы?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Назва сеткі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрас Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Заўсёды дазваляць у гэтай сетцы"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Няправільны ўзор разблакіроўкі"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Няправільны пароль"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Занадта шмат няўдалых спроб.\nПаспрабуйце зноў праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Экстранны выклік"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Паўтарыце спробу. Спроба <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> з <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Вашы даныя будуць выдалены"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Калі вы ўведзяце няправільны ўзор разблакіроўкі яшчэ раз, даныя з гэтай прылады будуць выдалены."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Калі пачынаецца абагульванне, запіс ці трансляцыя, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымлівае доступ да ўсяго змесціва, якое паказваецца на экране ці прайграецца на прыладзе. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Калі пачынаецца абагульванне, запіс ці трансляцыя змесціва праграмы, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымлівае доступ да ўсяго змесціва, якое паказваецца ці прайграецца ў праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Пачаць"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" адключыла гэты параметр"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Пачаць трансляцыю?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Калі адбываецца трансляцыя, Android мае доступ да ўсяго змесціва, якое паказваецца на экране ці прайграецца на прыладзе. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Калі адбываецца трансляцыя змесціва праграмы, Android мае доступ да ўсяго змесціва, якое паказваецца ці прайграецца ў праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Памочнік гатовы выконваць каманды"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string>
     <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Мікрафон і камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Нядаўна выкарыстоўваліся праграмамі"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Паглядзець нядаўні доступ"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 38781a4..896756d 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Друго устройство е заявило промяна на езика на системата"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Промяна на езика"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Текущ език: Запазване"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Споделяне на Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Разрешаване на безжичното отстраняване на грешки?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Име на мрежата (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдрес на Wi‑Fi мрежата (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Винаги да се разрешава в тази мрежа"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Грешна фигура"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Грешна парола"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Твърде много неправилни опити.\nОпитайте отново след <xliff:g id="NUMBER">%d</xliff:g> секунди."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Спешен случай"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Опитайте отново. Опит <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> от <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Данните ви ще бъдат изтрити"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ако въведете неправилна фигура при следващия опит, данните от това устройство ще бъдат изтрити."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Когато споделяте, записвате или предавате, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има достъп до всичко, което се вижда на екрана ви или се възпроизвежда на устройството ви. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Когато споделяте, записвате или предавате дадено приложение, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има достъп до всичко, което се показва или възпроизвежда в него. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Стартиране"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> деактивира тази опция"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Искате ли да стартирате предаване?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Когато предавате, Android има достъп до всичко, което се вижда на екрана ви или се възпроизвежда на устройството ви. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Когато предавате дадено приложение, Android има достъп до всичко, което се показва или възпроизвежда в него. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Функцията за активиране на Асистент е включена"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Скорошно използване на приложението"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Вижте скорошния достъп"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index b6b539c..5c1b445 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"অন্য ডিভাইসের দ্বারা সিস্টেমের ভাষা পরিবর্তনের অনুরোধ করা হয়েছে"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ভাষা পরিবর্তন করুন"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"বর্তমান ভাষা রাখুন"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ওয়াই-ফাই শেয়ার করুন"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"এই নেটওয়ার্কে ওয়্যারলেস ডিবাগিংয়ের অনুমতি দেবেন?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"নেটওয়ার্কের নাম (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nওয়াই-ফাই অ্যাড্রেস (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"এই নেটওয়ার্কে সবসময় অনুমতি দিন"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ভুল প্যাটার্ন"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ভুল পাসওয়ার্ড"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"অনেকবার ভুল চেষ্টা করা হয়েছে। \n<xliff:g id="NUMBER">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন।"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"জরুরি"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"আবার চেষ্টা করুন। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> বারের মধ্যে <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> বার চেষ্টা করা হয়েছে।"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"আপনার ডেটা মুছে দেওয়া হবে"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"আপনি পরের বারও ভুল প্যাটার্ন আঁকলে এই ডিভাইসের ডেটা মুছে দেওয়া হবে।"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"আপনি শেয়ার, রেকর্ড বা কাস্ট করার সময়, স্ক্রিনে দৃশ্যমান বা ডিভাইসে চালানো সব কিছুই <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> অ্যাক্সেস করতে পারবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"আপনি কোনও অ্যাপ শেয়ার, রেকর্ড বা কাস্ট করার সময়, সেই অ্যাপে দেখা যায় বা চালানো হয় এমন সব কিছু <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> অ্যাক্সেস করতে পারবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"শুরু করুন"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> এই বিকল্পটি বন্ধ করে দিয়েছে"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"কাস্ট করা শুরু করবেন?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"আপনি কাস্ট করার সময়, স্ক্রিনে দৃশ্যমান বা ডিভাইসে চালানো সবকিছুই Android অ্যাক্সেস করতে পারবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"আপনি কোনও অ্যাপ কাস্ট করার সময়, ওই অ্যাপে দেখানো বা চালানো হয় এমন সবকিছুই Android অ্যাক্সেস করতে পারবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"অ্যাসিস্ট্যান্ট আপনার কথা শোনার জন্য চালু করা আছে"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string>
     <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"মাইক্রোফোন ও ক্যামেরা"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"সম্প্রতি ব্যবহার করা অ্যাপ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"সাম্প্রতিক অ্যাক্সেস দেখুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index b5fa00e..63f62f1 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Promjenu jezika sistema je zatražio drugi uređaj"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Promijeni jezik"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zadrži trenutni jezik"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Dijeli WiFi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Dozvoliti bežično otklanjanje grešaka na ovoj mreži?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa WiFi mreže (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Uvijek dozvoli na ovoj mreži"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Pogrešan uzorak"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Pogrešna lozinka"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Previše pogrešnih pokušaja.\n Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Hitan slučaj"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Pokušajte ponovo. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. pokušaj od <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vaši podaci će se izbrisati"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ako u sljedećem pokušaju unesete neispravan uzorak, podaci ovog uređaja će se izbrisati."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kada dijelite, snimate ili emitirate, aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što je vidljivo na ekranu ili što se reproducira na uređaju. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kada dijelite, snimate ili emitirate aplikaciju, aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Pokreni"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućila tu opciju"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Pokrenuti emitiranje?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kada emitirate, Android ima pristup svemu što je vidljivo na ekranu ili što se reproducira na uređaju. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kada emitirate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Pažnja Asistenta je uključena"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string>
     <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavno korištenje aplikacije"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Prikaži nedavni pristup"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index fea2ee6..f54a0ac 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Un altre dispositiu ha sol·licitat canviar l\'idioma del sistema"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Canvia l\'idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantén l\'idioma actual"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Comparteix la Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Vols permetre la depuració sense fil en aquesta xarxa?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nom de la xarxa (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdreça Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permet sempre en aquesta xarxa"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Patró incorrecte"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Contrasenya incorrecta"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Has superat el nombre d\'intents incorrectes permesos.\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER">%d</xliff:g> segons."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergència"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Torna-ho a provar. Intent <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Se suprimiran les teves dades"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Si tornes a introduir un patró incorrecte, se suprimiran les dades del dispositiu."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Quan comparteixes, graves o emets contingut, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi al dispositiu. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Quan comparteixes, graves o emets contingut, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi a l\'aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Inicia"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha desactivat aquesta opció"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Vols iniciar una emissió?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Quan emets contingut, Android té accés a qualsevol cosa que es vegi a la pantalla o que es reprodueixi al dispositiu. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Quan emets una aplicació, Android té accés a qualsevol cosa que es mostri o que es reprodueixi en aquella aplicació. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"L\'Assistent està activat"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string>
     <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micròfon i càmera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ús recent de l\'aplicació"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Mostra l\'accés recent"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 339ba71..1bfe1f4 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Jiné zařízení požádalo o změnu systémového jazyka"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Změnit jazyk"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zachovat stávající jazyk"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Sdílení sítě Wi-Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Povolit v této síti bezdrátové ladění?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Název sítě (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"V této síti vždy povolit"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Nesprávné gesto"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Nesprávné heslo"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Příliš mnoho neplatných pokusů.\nZkuste to znovu za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Stav nouze"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Zkuste to znovu. Pokus <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> z <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vaše data budou smazána"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Pokud při příštím pokusu zadáte nesprávné gesto, data v tomto zařízení budou smazána."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Během sdílení, nahrávání nebo odesílání má <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> přístup k veškerému obsahu, který je viditelný na obrazovce nebo se přehrává v zařízení. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Během sdílení, nahrávání nebo odesílání aplikace má <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> přístup k veškerému obsahu, který je v dané aplikaci zobrazen nebo přehráván. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Začít"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> tuto možnost zakázala"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Začít odesílat?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Během odesílání má Android přístup ke všemu, co je viditelné na obrazovce nebo se přehrává v zařízení. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Během odesílání aplikace má Android přístup k veškerému obsahu, který je v dané aplikaci zobrazen nebo přehráván. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Pozornost Asistenta je zapnutá"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string>
     <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon a fotoaparát"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávné použití aplikacemi"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobrazit nedávný přístup"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 79ba451..17853e7 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"En anden enhed har anmodet om en ændring af systemsproget"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Skift sprog"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Behold nuværende sprog"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Del Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Vil du tillade trådløs fejlretning på dette netværk?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Netværksnavn (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adresse (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Tillad altid på dette netværk"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Forkert mønster"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Forkert adgangskode"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"For mange mislykkede forsøg. \nPrøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Nødsituation"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Prøv igen. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. forsøg ud af <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Dine data bliver slettet"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Hvis du angiver et forkert mønster i næste forsøg, slettes dataene på denne enhed."</string>
@@ -182,11 +180,11 @@
     <string name="fingerprint_re_enroll_dialog_content" msgid="4866561176695984879">"Hvis du vil konfigurere oplåsning med fingeraftryk igen, bliver dine nuværende fingeraftryksbilleder og -modeller slettet.\n\nNår de er slettet, skal du konfigurere oplåsning med fingeraftryk igen for at bruge dit fingeraftryk til at låse din telefon op eller verificere din identitet."</string>
     <string name="fingerprint_re_enroll_dialog_content_singular" msgid="3083663339787381218">"Hvis du vil konfigurere oplåsning med fingeraftryk igen, bliver dine nuværende fingeraftryksbilleder og -modeller slettet.\n\nNår de er slettet, skal du konfigurere oplåsning med fingeraftryk igen for at bruge dit fingeraftryk til at låse din telefon op eller verificere din identitet."</string>
     <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"Oplåsning med fingeraftryk kunne ikke konfigureres. Gå til Indstillinger for at prøve igen."</string>
-    <string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Konfigurer ansigtslås igen"</string>
-    <string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Ansigtslås"</string>
-    <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Konfigurer ansigtslås"</string>
-    <string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"Hvis du vil konfigurere ansigtslås igen, bliver din nuværende ansigtsmodel slettet.\n\nDu skal konfigurere funktionen igen for at bruge ansigtsgenkendelse til at låse din telefon op."</string>
-    <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Ansigtslås kunne ikke konfigureres. Gå til Indstillinger for at prøve igen."</string>
+    <string name="face_re_enroll_notification_title" msgid="1850838867718410520">"Konfigurer ansigtsoplåsning igen"</string>
+    <string name="face_re_enroll_notification_name" msgid="7384545252206120659">"Ansigtsoplåsning"</string>
+    <string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"Konfigurer ansigtsoplåsning"</string>
+    <string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"Hvis du vil konfigurere ansigtsoplåsning igen, bliver din nuværende ansigtsmodel slettet.\n\nDu skal konfigurere funktionen igen for at bruge ansigtsgenkendelse til at låse din telefon op."</string>
+    <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Ansigtsoplåsning kunne ikke konfigureres. Gå til Indstillinger for at prøve igen."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykssensoren"</string>
     <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tryk på oplåsningsikonet for at fortsætte"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string>
@@ -194,7 +192,7 @@
     <skip />
     <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansigt kan ikke genkendes"</string>
     <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Brug fingeraftryk i stedet"</string>
-    <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansigtslås er utilgængelig"</string>
+    <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansigtsoplåsning er utilgængelig"</string>
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tilsluttet."</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tilsluttet <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -369,7 +367,7 @@
     <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"Låst op via ansigtsgenkendelse"</string>
     <string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"Ansigtet er genkendt"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Stryg opad for at prøve igen"</string>
-    <string name="accesssibility_keyguard_retry" msgid="8880238862712870676">"Stryg opad for at prøve ansigtslåsen igen"</string>
+    <string name="accesssibility_keyguard_retry" msgid="8880238862712870676">"Stryg opad for at prøve ansigtsoplåsning igen"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Lås op for at bruge NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Denne enhed tilhører din organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Denne enhed tilhører <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Når du deler, optager eller caster, har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> adgang til alt, der er synligt på din skærm eller afspilles på din enhed. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Når du deler, optager eller caster en app, har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> adgang til alt, der vises eller afspilles i den pågældende app. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Start"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> har deaktiveret denne valgmulighed"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Vil du begynde at caste?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Når du caster, har Android adgang til alt, der vises på din skærm eller afspilles på din enhed. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Når du caster en app, har Android adgang til alt, der vises eller afspilles i den pågældende app. Vær derfor forsigtig med ting såsom adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent lytter"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon og kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Seneste brug af apps"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se seneste adgang"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4f08805..822ab27 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Von einem anderen Gerät wurde eine Änderung der Systemsprache angefordert"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Sprache ändern"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Aktuelle Sprache nutzen"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"WLAN teilen"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Debugging über WLAN in diesem Netzwerk zulassen?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Netzwerkname (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWLAN-Adresse (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Immer in diesem Netzwerk zulassen"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Falsches Muster"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Falsches Passwort"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Zu viele Fehlversuche.\nBitte probiere es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden noch einmal."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Notfall"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Bitte probier es noch einmal. Versuch <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> von <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Deine Daten werden gelöscht"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Wenn du beim nächsten Versuch ein falsches Muster eingibst, werden die Daten auf diesem Gerät gelöscht."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Beim Teilen, Aufnehmen oder Streamen hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Beim Teilen, Aufnehmen oder Streamen einer App hat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder von ihr wiedergegeben werden. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Starten"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> hat diese Option deaktiviert"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Stream starten?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Beim Streamen hat Android Zugriff auf alle Inhalte, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Beim Streamen einer App hat Android Zugriff auf alle Inhalte, die in dieser App sichtbar sind oder von ihr wiedergegeben werden. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant-Aktivierung an"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string>
     <string name="install_app" msgid="5066668100199613936">"App installieren"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon &amp; Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Kürzliche App-Nutzung"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kürzliche Zugriffe ansehen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 63337fd..c33b753 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ζητήθηκε αλλαγή της γλώσσας συστήματος από άλλη συσκευή"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Αλλαγή γλώσσας"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Διατήρ. τρέχουσας γλώσσας"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Κοινοποίηση Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Να επιτρέπεται ασύρματος εντοπ. σφαλ. στο δίκτυο;"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Όνομα δικτύου (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nΔιεύθυνση Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Να επιτρέπεται πάντα σε αυτό το δίκτυο"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Εσφαλμένο μοτίβο"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Εσφαλμένος κωδικός πρόσβασης"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Πάρα πολλές αποτυχημένες προσπάθειες.\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Έκτακτη ανάγκη"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Προσπαθήστε ξανά. Προσπάθεια <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> από <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Τα δεδομένα σας θα διαγραφούν"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Εάν εισαγάγετε εσφαλμένο μοτίβο στην επόμενη προσπάθεια, τα δεδομένα αυτής της συσκευής θα διαγραφούν."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Όταν κάνετε κοινή χρήση, εγγραφή ή μετάδοση, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη σας ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Όταν κάνετε κοινή χρήση, εγγραφή ή μετάδοση μιας εφαρμογής, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Έναρξη"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απενεργοποίησε αυτήν την επιλογή"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Έναρξη μετάδοσης;"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Όταν κάνετε μετάδοση, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη σας ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Όταν κάνετε μετάδοση μιας εφαρμογής, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Ο Βοηθός βρίσκεται σε αναμονή"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string>
     <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Μικρόφωνο και Κάμερα"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Πρόσφατη χρήση εφαρμογής"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Εμφάνιση πρόσφατης πρόσβασης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 7fbd4bf..901459d 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"System language change requested by another device"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Change language"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Keep current language"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Share Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Allow wireless debugging on this network?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Network Name (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Address (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Always allow on this network"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Wrong pattern"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Wrong password"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Too many incorrect attempts.\nTry again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergency"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Try again. Attempt <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> of <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Your data will be deleted"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"If you enter an incorrect pattern on the next attempt, this device’s data will be deleted."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"When you’re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"When you’re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Start"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> has disabled this option"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Start casting?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"Enable display"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 0e50776..01aa637 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"System language change requested by another device"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Change language"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Keep current language"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Share Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Allow wireless debugging on this network?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Network Name (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Address (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Always allow on this network"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Wrong pattern"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Wrong password"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Too many incorrect attempts.\nTry again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergency"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Try again. Attempt <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> of <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Your data will be deleted"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"If you enter an incorrect pattern on the next attempt, this device’s data will be deleted."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"When you’re sharing, recording, or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"When you’re sharing, recording, or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Start"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> has disabled this option"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Start casting?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"Enable display"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone &amp; Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 7fbd4bf..901459d 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"System language change requested by another device"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Change language"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Keep current language"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Share Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Allow wireless debugging on this network?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Network Name (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Address (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Always allow on this network"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Wrong pattern"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Wrong password"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Too many incorrect attempts.\nTry again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergency"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Try again. Attempt <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> of <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Your data will be deleted"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"If you enter an incorrect pattern on the next attempt, this device’s data will be deleted."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"When you’re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"When you’re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Start"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> has disabled this option"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Start casting?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"Enable display"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 7fbd4bf..901459d 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"System language change requested by another device"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Change language"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Keep current language"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Share Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Allow wireless debugging on this network?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Network Name (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Address (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Always allow on this network"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Wrong pattern"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Wrong password"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Too many incorrect attempts.\nTry again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergency"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Try again. Attempt <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> of <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Your data will be deleted"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"If you enter an incorrect pattern on the next attempt, this device’s data will be deleted."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"When you’re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"When you’re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Start"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> has disabled this option"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Start casting?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant attention on"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
     <string name="install_app" msgid="5066668100199613936">"Install app"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"Enable display"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone and Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app use"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"See recent access"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 876bb0e..c496aee 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎System language change requested by another device‎‏‎‎‏‎"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎Change language‎‏‎‎‏‎"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎Keep current language‎‏‎‎‏‎"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‎‎Share Wi‑Fi‎‏‎‎‏‎"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎Allow wireless debugging on this network?‎‏‎‎‏‎"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‎Network Name (SSID)‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="SSID_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Wi‑Fi Address (BSSID)‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="BSSID_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎Always allow on this network‎‏‎‎‏‎"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‏‎Wrong pattern‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎Wrong password‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‎‎Too many incorrect attempts.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎Emergency‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‎Try again. Attempt ‎‏‎‎‏‏‎<xliff:g id="ATTEMPTS_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‏‎Your data will be deleted‎‏‎‎‏‎"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎If you enter an incorrect pattern on the next attempt, this device’s data will be deleted.‎‏‎‎‏‎"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎When you’re sharing, recording, or casting, ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎ has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.‎‏‎‎‏‎"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎When you’re sharing, recording, or casting an app, ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎ has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.‎‏‎‎‏‎"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎Start‎‏‎‎‏‎"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has disabled this option‎‏‎‎‏‎"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‎‏‎‏‏‎Start casting?‎‏‎‎‏‎"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.‎‏‎‎‏‎"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.‎‏‎‎‏‎"</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎Assistant attention on‎‏‎‎‏‎"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎Set default notes app in Settings‎‏‎‎‏‎"</string>
     <string name="install_app" msgid="5066668100199613936">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎Install app‎‏‎‎‏‎"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎Mirror to external display?‎‏‎‎‏‎"</string>
+    <string name="enable_display" msgid="8308309634883321977">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎Enable display‎‏‎‎‏‎"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎Microphone &amp; Camera‎‏‎‎‏‎"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎Recent app use‎‏‎‎‏‎"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎See recent access‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e5d197d..3653839 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Cambio de idioma del sistema solicitado por otro dispositivo"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantener el idioma actual"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Compartir Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"¿Quieres permitir la depuración inalámbrica en esta red?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nombre de red (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nDirección Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir siempre en esta red"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Patrón incorrecto"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Contraseña incorrecta"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Demasiados intentos incorrectos.\nVuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergencia"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Vuelve a intentarlo. Intento <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Se borrarán tus datos"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Si ingresas un patrón incorrecto en el próximo intento, se borrarán los datos de este dispositivo."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Cuando compartas, grabes o transmitas contenido, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo lo que sea visible en la pantalla o que reproduzcas en el dispositivo. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Cuando compartas, grabes o transmitas una app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo el contenido que se muestre o que reproduzcas en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Iniciar"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> inhabilitó esta opción"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"¿Quieres comenzar a transmitir contenido?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Cuando transmitas contenido, Android podrá acceder a todo lo que sea visible en la pantalla o que reproduzcas en el dispositivo. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Cuando transmitas una app, Android podrá acceder a todo el contenido que se muestre o que reproduzcas en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistente está prestando atención"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono y cámara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso reciente en apps"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver accesos recientes"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c2a6b71..0680821 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Otro dispositivo ha solicitado un cambio en el idioma del sistema"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Seguir en este idioma"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Compartir Wi-Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"¿Permitir la depuración inalámbrica en esta red?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nombre de la red (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nDirección Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir siempre en esta red"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Patrón incorrecto"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Contraseña incorrecta"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Demasiados intentos fallidos.\n Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergencia"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Vuelve a intentarlo. Intento <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Tus datos se eliminarán"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Si vuelves a introducir un patrón incorrecto, los datos de este dispositivo se eliminarán."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Cuando compartes, grabas o envías contenido, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> puede acceder a todo lo que se muestre en la pantalla o se reproduzca en tu dispositivo. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Cuando compartes, grabas o envías una aplicación, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> puede acceder a todo lo que se muestre o se reproduzca en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Empezar"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha inhabilitado esta opción"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"¿Empezar a enviar contenido?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Cuando envías contenido, Android puede acceder a todo lo que se muestre en la pantalla o se reproduzca en tu dispositivo. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Cuando envías una aplicación, Android puede acceder a todo lo que se muestre o se reproduzca en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"El Asistente está activado"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono y cámara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso reciente en aplicaciones"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acceso reciente"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3817e78..988d4d7 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Teine seade taotles süsteemi keele muutmist"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Muuda keelt"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Kasuta praegust keelt"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"WiFi jagamine"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Kas lubada selles võrgus juhtmevaba silumine?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Võrgu nimi (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWiFi-võrgu aadress (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Luba selles võrgus alati"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Vale muster"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Vale parool"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Liiga palju valesid katseid.\nProovige <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast uuesti."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Hädaabi"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Proovige uuesti. Katse <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Teie andmed kustutatakse"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Kui sisestate järgmisel katsel vale mustri, kustutatakse selle seadme andmed."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kui jagate, salvestate või kannate üle, on rakendusel <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> juurdepääs kõigele, mis on teie ekraanikuval nähtaval või mida teie seadmes esitatakse. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kui jagate, salvestate või kannate rakendust üle, on rakendusel <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> juurdepääs kõigele, mida selles rakenduses kuvatakse või esitatakse. Seega olge paroolide, makseteabe, sõnumite, fotode, heli ja videoga ettevaatlik."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Alusta"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> on selle valiku keelanud"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Kas alustada ülekandmist?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kui kannate üle, on Androidil juurdepääs kõigele, mis on teie ekraanikuval nähtaval või mida teie seadmes esitatakse. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Rakenduse ülekandmise ajal on Androidil juurdepääs kõigele, mis on selles rakenduses nähtaval või mida selles esitatakse. Seega olge paroolide, makseteabe, sõnumite, fotode, heli ja videoga ettevaatlik."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent on aktiveeritud"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
     <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ja kaamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Rakenduste hiljutine kasutamine"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Kuva hiljutine juurdepääs"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 2ad43cc..71cb074 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Beste gailu batek sistemaren hizkuntza aldatzeko eskatu du"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Aldatu hizkuntza"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantendu oraingo hizkuntza"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Partekatu wifia"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Hari gabeko arazketa sare honetan erabiltzeko baimena eman nahi duzu?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Sarearen izena (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWifi-helbidea (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Eman baimena beti sare honetan"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Eredua ez da zuzena"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Pasahitza ez da zuzena"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Saiakera oker gehiegi egin dituzu.\nSaiatu berriro <xliff:g id="NUMBER">%d</xliff:g> segundo barru."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Larrialdi-deia"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Saiatu berriro. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> saiakera."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Datuak ezabatuko dira"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Hurrengo saiakeran eredua oker marrazten baduzu, gailuko datuak ezabatuko dira."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Edukia partekatzen, grabatzen edo igortzen ari zarenean, pantailan ikusgai dagoen edo gailuan erreproduzitzen ari den guztia atzi dezake <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Aplikazio bat partekatzen, grabatzen edo igortzen ari zarenean, aplikazio horretan ikusgai dagoen edo bertan erreproduzitzen ari den guztia atzi dezake <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Hasi"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak aukera desgaitu du"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Igortzen hasi nahi duzu?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Edukia igortzen ari zarenean, pantailan ikusgai dagoen edo gailuan erreproduzitzen ari den guztia atzi dezake Android-ek. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Aplikazio bat igortzen ari zarenean, aplikazio horretan ikusgai dagoen edo bertan erreproduzitzen ari den guztia atzi dezake Android-ek. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Laguntzailea zerbitzuak arreta jarrita dauka"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofonoa eta kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Aplikazioen azken erabilera"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ikusi azkenaldiko sarbidea"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 8263639..8902103 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"دستگاه دیگری درخواست کرده است زبان سیستم تغییر کند"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"تغییر زبان"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"حفظ زبان فعلی"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"‏اشتراک‌گذاری Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"اشکال‌زدایی بی‌سیم در این شبکه مجاز شود؟"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"‏نام شبکه (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nنشانی Wi‑Fi (BSSID)‎\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"همیشه در این شبکه مجاز شود"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"الگو اشتباه است"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"گذرواژه اشتباه است"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"تلاش‌های نادرست بسیاری انجام شده است.\nپس از <xliff:g id="NUMBER">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"اضطراری"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"دوباره امتحان کنید. تلاش <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> از <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"داده‌هایتان حذف خواهد شد"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"اگر در تلاش بعدی الگوی نادرستی وارد کنید، داده‌های این دستگاه حذف خواهد شد."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"وقتی درحال هم‌رسانی، ضبط، یا پخش محتوا هستید، <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> به همه محتوایی که در صفحه‌تان نمایان است یا در دستگاهتان پخش می‌شود دسترسی دارد. درنتیجه مراقب چیزهایی مثل گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، عکس‌ها، و صدا و تصویر باشید."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"وقتی درحال هم‌رسانی، ضبط، یا پخش محتوای برنامه‌ای هستید، <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> به همه محتوایی که در آن برنامه نمایان است یا پخش می‌شود دسترسی دارد. درنتیجه مراقب چیزهایی مثل گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، عکس‌ها، و صدا و تصویر باشید."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"شروع"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>این گزینه را غیرفعال کرده است"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"پخش محتوا شروع شود؟"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"‏وقتی محتوا پخش می‌کنید، Android به همه محتوایی که در صفحه‌تان نمایان است یا در دستگاهتان پخش می‌شود دسترسی دارد. درنتیجه مراقب چیزهایی مثل گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، عکس‌ها، و صدا و تصویر باشید."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"‏وقتی محتوای برنامه‌ای را پخش می‌کنید، Android به همه محتوایی که در آن برنامه نمایان است یا پخش می‌شود دسترسی دارد. درنتیجه مراقب چیزهایی مثل گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، عکس‌ها، و صدا و تصویر باشید."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"توجه «دستیار» روشن است"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیش‌فرض یادداشت را در «تنظیمات» تنظیم کنید"</string>
     <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"میکروفون و دوربین"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"استفاده اخیر از برنامه"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"دیدن دسترسی اخیر"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dc0e52d..7e2ab65 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Toiselta laitteelta pyydetty järjestelmän kielen vaihtamista"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Vaihda kieltä"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Pidä nykyinen kieli"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Jaa Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Sallitaanko langaton virheenkorjaus tässä verkossa?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Verkon nimi (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi-Fin osoite (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Salli aina tässä verkossa"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Väärä kuvio"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Väärä salasana"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Liian monta virheellistä yritystä.\nYritä uudelleen <xliff:g id="NUMBER">%d</xliff:g> sekunnin kuluttua."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Hätätilanne"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Yritä uudelleen. Yritys <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Datasi poistetaan"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Jos annat väärän kuvion seuraavalla yrityskerralla, tämän laitteen data poistetaan."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kun jaat, tallennat tai striimaat, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> saa pääsyn kaikkeen näytölläsi näkyvään tai laitteellasi toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kun jaat, tallennat tai striimaat sovellusta, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> saa pääsyn kaikkeen sovelluksessa näkyvään tai toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Aloita"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> on poistanut vaihtoehdon käytöstä"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Aloitetaanko striimaus?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kun striimaat, Android saa pääsyn kaikkeen näytölläsi näkyvään tai laitteellasi toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kun striimaat sovellusta, Android saa pääsyn kaikkeen sovelluksessa näkyvään tai toistettuun sisältöön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant on aktiivinen"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
     <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoni ja kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Sovellusten viimeaikainen käyttö"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Katso viimeaikainen käyttö"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index dcaaef0..a863623 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Un autre appareil demande de changer la langue du système"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Changer la langue"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Garder la langue actuelle"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Partager le Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Autoriser le débogage sans fil sur ce réseau?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nom du réseau (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresse Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Toujours autoriser sur ce réseau"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Schéma incorrect"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Mot de passe incorrect"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Trop de tentatives incorrectes. \nRéessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Appel d\'urgence"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Réessayez. Tentative <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> sur <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vos données seront supprimées"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Si vous entrez un schéma incorrect à la prochaine tentative, les données de cet appareil seront supprimées."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Lorsque vous partagez, enregistrez ou diffusez, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Lorsque vous partagez, enregistrez ou diffusez une application, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Commencer"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> a désactivé cette option"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Commencer la diffusion?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Lorsque vous diffusez, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Lorsque vous diffusez une application, Android a accès à tout ce qui est visible sur votre écran ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages, les photos et les contenus audio et vidéo."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant à l\'écoute"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microphone et appareil photo"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applications"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Afficher l\'accès récent"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0fbf014..a3920de 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Changement de langue système demandé par un autre appareil"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Changer de langue"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Garder la langue actuelle"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Partager le Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Autoriser le débogage sans fil sur ce réseau ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nom du réseau (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresse Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Toujours autoriser sur ce réseau"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Schéma incorrect"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Mot de passe incorrect"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Trop de tentatives incorrectes.\nVeuillez réessayer dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Urgence"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Réessayez. Tentative <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> sur <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Risque de perte des données"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Si vous dessinez un schéma incorrect lors de la prochaine tentative, les données de cet appareil seront supprimées."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Lorsque vous partagez, enregistrez ou castez, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages, photos et contenus audio et vidéo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Lorsque vous partagez, enregistrez ou castez une appli, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages et contenus audio et vidéo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Commencer"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> a désactivé cette option"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Commencer à caster ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Lorsque vous castez, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages, photos et contenus audio et vidéo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Lorsque vous castez une appli, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Faites donc attention aux éléments tels que les mots de passe, détails de mode de paiement, messages et contenus audio et vidéo."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant à l\'écoute"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micro et caméra"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilisation récente par les applis"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consulter les accès récents"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 27b57e4..344c0d4 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Outro dispositivo solicitou un cambio do idioma do sistema"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambiar idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma actual"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Compartir wifi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Queres permitir a depuración sen fíos nesta rede?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome de rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEnderezo wifi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir sempre nesta rede"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"O padrón é incorrecto"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"O contrasinal é incorrecto"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Realizáronse demasiados intentos incorrectos.\nTéntao de novo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emerxencia"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Téntao de novo. Intento <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Eliminaranse os teus datos"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Se indicas un padrón incorrecto no seguinte intento, eliminaranse os datos deste dispositivo."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Cando compartes, gravas ou emites contido, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ten acceso a todo o que se vexa na pantalla ou se reproduza no teu dispositivo. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Cando compartes, gravas ou emites unha aplicación, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ten acceso a todo o que se vexa ou se reproduza nela. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Iniciar"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> desactivou esta opción"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Queres comezar a emitir contido?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Cando emites contido, Android ten acceso a todo o que se vexa na pantalla ou se reproduza no teu dispositivo. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Cando emites unha aplicación, Android ten acceso a todo o que se vexa ou se reproduza nela. Polo tanto, debes ter coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como o contido de audio e de vídeo."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"A atención do Asistente está activada"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrófono e cámara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente por parte de aplicacións"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acceso recente"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d62fd99..a32c78fc 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"બીજા ડિવાઇસ દ્વારા સિસ્ટમની ભાષા બદલવાની વિનંતી કરવામાં આવી છે"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ભાષા બદલો"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"વર્તમાન ભાષા રાખો"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"વાઇ-ફાઇ શેર કરો"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"આ નેટવર્ક પર વાયરલેસ ડિબગીંગની મંજૂરી આપીએ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"નેટવર્કનું નામ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nવાઇ-ફાઇ ઍડ્રેસ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"આ નેટવર્ક પર હંમેશા મંજૂરી આપો"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ખોટી પૅટર્ન"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ખોટો પાસવર્ડ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ઘણા વધારે ખોટા પ્રયત્નો. \n <xliff:g id="NUMBER">%d</xliff:g> સેકંડમાં ફરી પ્રયાસ કરો."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ઇમર્જન્સી"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ફરી પ્રયાસ કરો. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> માંથી <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> પ્રયત્ન."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"તમારો ડેટા ડિલીટ કરવામાં આવશે"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"જો તમે આગલા પ્રયત્નમાં ખોટી પૅટર્ન દાખલ કરશો, તો આ ડિવાઇસનો ડેટા ડિલીટ કરવામાં આવશે."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"જ્યારે તમે શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પર દેખાતી હોય કે તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી બધી વસ્તુનો ઍક્સેસ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> પાસે હોય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"જ્યારે તમે કોઈ ઍપ શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી બધી વસ્તુનો ઍક્સેસ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> પાસે હોય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"શરૂ કરો"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> દ્વારા આ વિકલ્પ બંધ કરવામાં આવ્યો છે"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"કાસ્ટ કરવાનું શરૂ કરીએ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"જ્યારે તમે કાસ્ટ કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પર દેખાતી કે તમારા ડિવાઇસ પર ચલાવવામાં આવતી બધી વસ્તુઓનો ઍક્સેસ Android પાસે હોય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"જ્યારે તમે ઍપને કાસ્ટ કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી બધી વસ્તુનો ઍક્સેસ Android પાસે હોય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant સક્રિય છે"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string>
     <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"માઇક્રોફોન અને કૅમેરા"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"તાજેતરનો ઍપનો વપરાશ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"તાજેતરનો ઍક્સેસ મેનેજ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 18774ae..c73b8f7 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"किसी दूसरे डिवाइस से, सिस्टम की भाषा बदलने का अनुरोध किया गया"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"भाषा बदलें"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"मौजूदा भाषा रखें"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"वाई-फ़ाई शेयर करें"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"क्या आप इस नेटवर्क पर वॉयरलेस डीबगिंग के इस्तेमाल की अनुमति देना चाहते हैं?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्क का नाम (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nवाई-फ़ाई का पता (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"इस नेटवर्क पर हमेशा अनुमति दें"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"गलत पैटर्न"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"गलत पासवर्ड"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"आपकी कोशिशें बहुत बार गलत हुई हैं.\nआप <xliff:g id="NUMBER">%d</xliff:g> सेकंड में फिर से कोशिश कर सकते हैं."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"आपातकालीन कॉल"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"फिर से कोशिश करें. आप <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> में से <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> बार कोशिश कर चुके हैं."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"आपका डेटा मिटा दिया जाएगा"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"अगर आप फिर से गलत पैटर्न डालते हैं, तो इस डिवाइस का डेटा मिटा दिया जाएगा."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"शेयर, रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> के पास स्क्रीन पर दिख रहे कॉन्टेंट या डिवाइस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, और डिवाइस पर चल रहे ऑडियो और वीडियो को लेकर सावधानी बरतें."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"किसी ऐप्लिकेशन को शेयर, रिकॉर्ड या कास्ट करते समय, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> के पास उस ऐप्लिकेशन पर दिख रहे कॉन्टेंट या उस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, और डिवाइस पर चल रहे ऑडियो और वीडियो को लेकर सावधानी बरतें."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"शुरू करें"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ने इस विकल्प को बंद कर दिया है"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"क्या मीडिया कास्ट करना है?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"कास्ट करते समय, Android के पास स्क्रीन पर दिख रहे कॉन्टेंट या डिवाइस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, और डिवाइस पर चल रहे ऑडियो और वीडियो को लेकर सावधानी बरतें."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"किसी ऐप्लिकेशन को कास्ट करते समय, Android के पास उस ऐप्लिकेशन पर दिख रहे कॉन्टेंट या उस पर चल रहे हर मीडिया का ऐक्सेस होता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, और डिवाइस पर चल रहे ऑडियो और वीडियो को लेकर सावधानी बरतें."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant आपकी बातें सुन रही है"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
     <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफ़ोन और कैमरा"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"हाल ही में इस्तेमाल करने वाला ऐप्लिकेशन"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हाल में ऐक्सेस करने वाले ऐप"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b684038..f9b220d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Drugi uređaj zatražio je promjenu jezika sustava"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Promijeni jezik"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zadrži trenutačni jezik"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Dijeli Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Dopustiti bežično otklanjanje pogrešaka na ovoj mreži?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Naziv mreže (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fija (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Uvijek dopusti na ovoj mreži"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Pogrešan uzorak"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Pogrešna zaporka"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Previše netočnih pokušaja.\nPokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Hitni slučaj"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Pokušajte ponovo. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. pokušaj od <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vaši će se podaci izbrisati"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ako pri sljedećem pokušaju unesete netočan uzorak, izbrisat će se podaci s ovog uređaja."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kad dijelite, snimate ili emitirate, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kad dijelite, snimate ili emitirate aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Pokreni"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> onemogućila je ovu opciju"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Želite li pokrenuti emitiranje?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kad emitirate, Android ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kad emitirate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Pažnja Asistenta je aktivirana"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalacija"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavna upotreba aplikacije"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Pogledajte nedavni pristup"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 26f60f9..0d40770 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Egy másik eszköz a rendszer nyelvének módosítását kéri"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Nyelvmódosítás"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Aktuális nyelv megtartása"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi megosztása"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Engedélyezi a vezeték nélküli hibakeresést ezen a hálózaton?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Hálózat neve (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-cím (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Mindig engedélyezze ezen a hálózaton"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Helytelen minta"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Helytelen jelszó"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Túl sok helytelen próbálkozás.\nPróbálja újra <xliff:g id="NUMBER">%d</xliff:g> másodperc múlva."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Vészhelyzet"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Próbálja újra. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. kísérlet, összesen: <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Adatai törlődni fognak"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Amennyiben helytelen mintát ad meg a következő kísérletnél, a rendszer törli az adatokat erről az eszközről."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Amikor Ön megosztást, rögzítést vagy átküldést végez, a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a képernyőn látható vagy az eszközön lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Amikor Ön megoszt, rögzít vagy átküld egy alkalmazást, a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> az adott appban látható vagy lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Indítás"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> letiltotta ezt a beállítást"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Elindítja az átküldést?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Amikor Ön átküldést végez, az Android a képernyőn látható vagy az eszközön lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Alkalmazás átküldése közben az Android az adott appban látható vagy lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"A Segéd figyel"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string>
     <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon és kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Legutóbbi alkalmazáshasználat"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Legutóbbi hozzáférés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index da38ae1..e64a8de3 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Մեկ այլ սարք համակարգի լեզվի փոփոխության հարցում է ուղարկել"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Փոխել լեզուն"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Թողնել ընթացիկ լեզուն"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Կիսվել Wi‑Fi-ով"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Թույլատրե՞լ անլար վրիպազերծումն այս ցանցում"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Ցանցի անվանումը (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-ի հասցեն (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Միշտ թույլատրել այս ցանցում"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Նախշը սխալ է"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Գաղտնաբառը սխալ է"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Չափից շատ սխալ փորձ է կատարվել:\nՆորից փորձեք <xliff:g id="NUMBER">%d</xliff:g> վայրկյանից:"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Արտակարգ իրավիճակ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Փորձեք նորից։ Փորձ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>՝ <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>-ից։"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Ձեր տվյալները կջնջվեն"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Հաջորդ փորձի ժամանակ սխալ նախշ մուտքագրելու դեպքում սարքի տվյալները կջնջվեն։"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Երբ դուք ցուցադրում, տեսագրում կամ հեռարձակում եք էկրանը, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածին հասանելի է լինում այն ամենը, ինչ տեսանելի է ձեր էկրանին և նվագարկվում է ձեր սարքում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Երբ դուք ցուցադրում, տեսագրում կամ հեռարձակում եք որևէ հավելվածի էկրանը, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածին հասանելի է լինում այն ամենը, ինչ ցուցադրվում կամ նվագարկվում է այդ հավելվածում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Սկսել"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ն անջատել է այս ընտրանքը"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Սկսե՞լ հեռարձակումը"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Երբ դուք հեռարձակում եք էկրանը, Android-ին հասանելի է լինում այն ամենը, ինչ տեսանելի է ձեր էկրանին կամ նվագարկվում է ձեր սարքում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Երբ դուք տեսագրում եք որևէ հավելվածի էկրանը, Android-ին հասանելի է լինում այն ամենը, ինչ ցուցադրվում կամ նվագարկվում է այդ հավելվածում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Օգնականը լսում է"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string>
     <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Խոսափող և տեսախցիկ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Հավելվածի վերջին օգտագործումը"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Տեսնել վերջին օգտագործումը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 320e125..d2a9747 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Perubahan bahasa sistem diminta oleh perangkat lain"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Ubah bahasa"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Pertahankan bahasa"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Bagikan Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Izinkan proses debug nirkabel di perangkat ini?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nama Jaringan (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAlamat Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Selalu izinkan di jaringan ini"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Pola salah"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Sandi salah"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Terlalu banyak kesalahan pola.\nCoba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> detik."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Keadaan Darurat"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Coba lagi. Percobaan <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> dari <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Data akan dihapus"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Jika Anda memasukkan pola yang salah saat mencoba lagi, data perangkat ini akan dihapus."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Jika Anda membagikan, merekam, atau mentransmisikan, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan memiliki akses ke semua hal yang ditampilkan di layar atau yang diputar di perangkat Anda. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Jika Anda membagikan, merekam, atau mentransmisikan suatu aplikasi, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan memiliki akses ke semua hal yang ditampilkan atau yang diputar di aplikasi tersebut. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio dan video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Mulai"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah menonaktifkan opsi ini"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Mulai mentransmisikan?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Jika mentransmisikan, Android akan memiliki akses ke semua hal yang ditampilkan di layar atau yang diputar di perangkat Anda. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Jika Anda mentransmisikan aplikasi, Android akan memiliki akses ke semua hal yang ditampilkan atau yang diputar di aplikasi tersebut. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
@@ -712,7 +709,7 @@
     <string name="switch_bar_off" msgid="5669805115416379556">"Nonaktif"</string>
     <string name="tile_unavailable" msgid="3095879009136616920">"Tidak tersedia"</string>
     <string name="accessibility_tile_disabled_by_policy_action_description" msgid="6958422730461646926">"pelajari lebih lanjut"</string>
-    <string name="nav_bar" msgid="4642708685386136807">"Bilah navigasi"</string>
+    <string name="nav_bar" msgid="4642708685386136807">"Menu navigasi"</string>
     <string name="nav_bar_layout" msgid="4716392484772899544">"Tata letak"</string>
     <string name="left_nav_bar_button_type" msgid="2634852842345192790">"Jenis tombol ekstra kiri"</string>
     <string name="right_nav_bar_button_type" msgid="4472566498647364715">"Jenis tombol ekstra kanan"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asisten sedang memerhatikan"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string>
     <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon &amp; Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Penggunaan aplikasi baru-baru ini"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Lihat akses terbaru"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 73f1745..d5bb28a 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Beiðni frá öðru tæki um að breyta tungumáli kerfis"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Breyta tungumáli"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Halda núverandi tungumáli"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Deila Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Viltu leyfa þráðlausa villuleit á þessu neti?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Heiti netkerfis (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi vistfang (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Leyfa alltaf á þessu neti"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Rangt mynstur"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Rangt aðgangsorð"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Of margar misheppnaðar tilraunir.\nReyndu aftur eftir <xliff:g id="NUMBER">%d</xliff:g> sekúndur."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Neyðartilvik"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Reyndu aftur. Tilraun <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> af <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Gögnunum þínum verður eytt"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ef þú slærð inn rangt mynstur í næstu tilraun verður gögnum tækisins eytt."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Þegar þú deilir, tekur upp eða varpar hefur<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aðgang að öllu sem sést á skjánum eða spilast í tækinu. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Þegar þú deilir, tekur upp eða varpar forriti hefur <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aðgang að öllu sem sést eða spilast í viðkomandi forriti. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Byrja"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> slökkti á þessum valkosti"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Byrja að varpa?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Þegar þú varpar hefur Android aðgang að öllu sem er sýnilegt á skjánum hjá þér eða spilast í tækinu þínu. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Þegar þú varpar forriti hefur Android aðgang að öllu sem sést eða spilast í viðkomandi forriti. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og myndskeið."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Hjálparinn er að hlusta"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string>
     <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Hljóðnemi og myndavél"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nýlega notað af forriti"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Sjá nýlegan aðgang"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0db6d7f..9f6228d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Cambio della lingua di sistema richiesto da un altro dispositivo"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Cambia lingua"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mantieni lingua attuale"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Condividi Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Consentire il debug wireless su questa rete?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome della rete (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nIndirizzo Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Consenti sempre su questa rete"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Sequenza errata"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Password errata"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Troppi tentativi errati.\nRiprova tra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergenza"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Riprova. Tentativo <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> di <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"I tuoi dati verranno eliminati"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Se al prossimo tentativo inserirai una sequenza sbagliata, i dati del dispositivo verranno eliminati."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Quando condividi, registri o trasmetti, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ha accesso a qualsiasi elemento visibile sul tuo schermo o in riproduzione sul tuo dispositivo. Presta quindi attenzione a password, dettagli sui pagamenti, messaggi, foto, audio e video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Quando condividi, registri o trasmetti un\'app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ha accesso a qualsiasi elemento visualizzato o riprodotto sull\'app. Presta quindi attenzione a password, dettagli sui pagamenti, messaggi, foto, audio e video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Inizia"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha disattivato questa opzione"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Iniziare a trasmettere?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Quando trasmetti, Android ha accesso a qualsiasi elemento visibile sul tuo schermo o in riproduzione sul tuo dispositivo. Presta quindi attenzione a password, dettagli sui pagamenti, messaggi, foto, audio e video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Quando trasmetti un\'app, Android ha accesso a qualsiasi elemento visualizzato o riprodotto sull\'app. Presta quindi attenzione a password, dettagli sui pagamenti, messaggi, foto, audio e video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"L\'assistente è attivo"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string>
     <string name="install_app" msgid="5066668100199613936">"Installa app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfono e fotocamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente da app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vedi accesso recente"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 0539635..44ad445 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"התקבלה בקשה ממכשיר אחר לשינוי שפת המערכת"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"שינוי שפה"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"השארת השפה הנוכחית"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"‏שיתוף Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"לאשר ניפוי באגים אלחוטי ברשת הזו?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"‏שם הרשת (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nכתובת Wi‑Fi‏ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"לאשר תמיד ברשת הזו"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"קו ביטול נעילה שגוי"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"סיסמה שגויה"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"יותר מדי ניסיונות שגויים.\nיש לנסות שוב בעוד <xliff:g id="NUMBER">%d</xliff:g> שניות."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"חירום"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"יש לנסות שוב. ניסיון <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> מתוך <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"הנתונים שלך יימחקו"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"הזנת קו ביטול נעילה שגוי בניסיון הבא תגרום למחיקת הנתונים במכשיר."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"‏בזמן שיתוף, הקלטה או העברה (cast) תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"‏בזמן שיתוף, הקלטה או העברה (cast) של אפליקציה, תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"התחלה"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> השביתה את האפשרות הזו"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"להתחיל את ההעברה?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"‏בזמן העברה (cast), תהיה ל-Android גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"‏בזמן העברה (cast) של אפליקציה, תהיה ל-Android גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"‏Assistant מאזינה"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string>
     <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"מיקרופון ומצלמה"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"נעשה שימוש לאחרונה באפליקציות"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"צפייה בהרשאות הגישה האחרונות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 967d2d1..5bd77fc 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"他のデバイスからシステム言語の変更が要求されました"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"言語を変更"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"現在の言語を変更しない"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi-Fi を共有"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"このネットワークでワイヤレス デバッグを許可しますか?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ネットワーク名(SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi アドレス(BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"このネットワークで常に許可する"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"パターンが正しくありません"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"パスワードが正しくありません"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"間違えた回数が上限を超えました。\n<xliff:g id="NUMBER">%d</xliff:g> 秒後にもう一度お試しください。"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"緊急通報"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"もう一度お試しください。入力回数: <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> 回"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"データが削除されます"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"パターンをあと 1 回間違えると、このデバイスのデータが削除されます。"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"共有、録画、キャスト中は、画面に表示される内容やデバイスで再生される内容に <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"アプリの共有、録画、キャスト中は、そのアプリで表示または再生される内容に <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"開始"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> がこのオプションを無効にしています"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"キャスト開始しますか?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"キャスト中は、画面に表示される内容やデバイスで再生される内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"アプリのキャスト中は、そのアプリで表示または再生される内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"アシスタントは起動済みです"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string>
     <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"マイクとカメラ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近のアプリの使用状況"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"最近のアクセスを表示"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 2a30da7..e0aa8ca 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"სისტემის ენის შეცვლა მოითხოვა სხვა მოწყობილობამ"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ენის შეცვლა"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"მიმდინარე ენის დატოვება"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi-ს გაზიარება"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"დაუშვებთ ამ ქსელში შეცდომების უსადენო გამართვას?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ქსელის სახელი (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi მისამართი (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ყოველთვის დაშვება ამ ქსელში"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ნიმუში არასწორია"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"პაროლი არასწორია"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"დაფიქსირდა ძალიან ბევრი არასწორი მცდელობა.\nცადეთ ხელახლა <xliff:g id="NUMBER">%d</xliff:g> წამში."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"საგანგებო სიტუაცია"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ცადეთ ხელახლა. მცდელობა <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> / <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>-დან."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"თქვენი მონაცემები წაიშლება"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"შემდეგი მცდელობისას განმბლოკავი ნიმუშის არასწორად შეყვანის შემთხვევაში, ამ მოწყობილობის მონაცემები წაიშლება."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"გაზიარების, ჩაწერის ან ტრანსლირების დროს, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ს აქვს წვდომა ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენს მოწყობილობაზე. ამიტომ იყავით ფრთხილად ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"აპის გაზიარებისას, ჩაწერისას ან ტრანსლირებისას, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ს წვდომა აქვს ყველაფერზე, რაც ჩანს ან იკვრება აპში. ამიტომ იყავით ფრთხილად ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"დაწყება"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>-მა გათიშა ეს ვარიანტი"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"გსურთ ტრანსლირების დაწყება?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"როდესაც თქვენ ტრანსლირებთ, ამ აპს აქვს წვდომა ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენს მოწყობილობაზე. ამიტომ იყავით ფრთხილად ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"როდესაც აპს ტრანსლირებთ, Android-ს წვდომა აქვს ყველაფერზე, რაც ჩანს ან იკვრება აპში. ამიტომ იყავით ფრთხილად ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"ასისტენტის ყურადღების ფუნქცია ჩართულია"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string>
     <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"ეკრანის ჩართვა"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"მიკროფონი და კამერა"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"აპის ბოლოდროინდელი გამოყენება"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ბოლო წვდომის ნახვა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 1adda91..917383b 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Басқа құрылғыдан жүйе тілін өзгерту туралы сұрау жіберілді."</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Тілді өзгерту"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Қазіргі тіл тұра берсін"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi желісін бөлісу"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Бұл желіде сымсыз түзетуге рұқсат етілсін бе?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Желі атауы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi мекенжайы (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Осы желіде үнемі рұқсат ету"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Өрнек қате."</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Құпия сөз қате."</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Тым көп қате енгізілді.\n<xliff:g id="NUMBER">%d</xliff:g> секундта әрекетті қайталаңыз."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Төтенше жағдай"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Әрекетті қайталаңыз. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> мүмкіндік, барлығы – <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Деректеріңіз жойылады"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Келесі әрекет кезінде қате өрнек енгізсеңіз, бұл құрылғылардың деректері жойылады."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Бөлісу, жазу не трансляциялау кезінде <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экраныңызда көрінетін не құрылғыңызда ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Қолданба экранын бөлісу, жазу не трансляциялау кезінде <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> онда көрінетін не ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Бастау"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы осы опцияны өшірді."</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Трансляциялау басталсын ба?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Трансляциялау кезінде Android жүйесі экраныңызда көрінетін не құрылғыңызда ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Қолданба экранын трансляциялау кезінде Android жүйесі қолданбада көрінетін не ойнатылатын барлық нәрсені пайдалана алады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant қосулы."</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string>
     <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон және камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Соңғы рет қолданбаның датчикті пайдалануы"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Соңғы рет пайдаланғандар"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index af1e3b5..92c2c1b 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ការប្ដូរភាសា​ប្រព័ន្ធដែលបានស្នើសុំ​ដោយ​ឧបករណ៍ផ្សេងទៀត"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"​ប្ដូរ​ភាសា"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"រក្សាភាសាបច្ចុប្បន្ន"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ចែករំលែក Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"អនុញ្ញាត​ការជួសជុល​ដោយឥតខ្សែ​នៅលើ​បណ្ដាញ​នេះ​ឬ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ឈ្មោះបណ្ដាញ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nអាសយដ្ឋាន Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"អនុញ្ញាត​នៅលើ​បណ្ដាញ​នេះ​ជានិច្ច"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"លំនាំមិនត្រឹមត្រូវ"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ពាក្យសម្ងាត់មិនត្រឹមត្រូវ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ការព្យាយាម​ចូលខុស​ច្រើនដងពេក។\nសូមព្យាយាម​ម្តងទៀត​ក្នុងរយៈពេល <xliff:g id="NUMBER">%d</xliff:g> វិនាទី។"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ពេលមានអាសន្ន"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"សូមព្យាយាម​ម្តងទៀត។ ការព្យាយាម <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> នៃ <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> ដង។"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ទិន្នន័យរបស់អ្នកនឹងត្រូវបានលុប"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"ប្រសិនបើអ្នក​បញ្ចូលលំនាំ​មិនត្រឹមត្រូវ នៅពេលព្យាយាមបញ្ចូល​លើកក្រោយ ទិន្នន័យរបស់​ឧបករណ៍នេះ​នឹងត្រូវបានលុប។"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬភ្ជាប់, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬចាក់នៅលើឧបករណ៍របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬភ្ជាប់កម្មវិធី, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មានសិទ្ធិចូលប្រើអ្វីៗដែលបង្ហាញ ឬចាក់នៅលើកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ចាប់ផ្ដើម"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> បានបិទជម្រើសនេះ"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"ចាប់ផ្តើមភ្ជាប់ឬ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"នៅពេលអ្នក​កំពុងភ្ជាប់, Android មានសិទ្ធិចូលប្រើអ្វីៗដែលអាចមើលឃើញនៅលើ​អេក្រង់របស់អ្នក ឬចាក់នៅលើឧបករណ៍របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"នៅពេលអ្នក​កំពុងភ្ជាប់កម្មវិធី, Android មានសិទ្ធិចូលប្រើអ្វីៗដែលបង្ហាញ ឬចាក់នៅលើកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"ភាពប្រុងប្រៀប​របស់ Google Assistant ត្រូវបានបើក"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string>
     <string name="install_app" msgid="5066668100199613936">"ដំឡើង​កម្មវិធី"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"មីក្រូហ្វូន និងកាមេរ៉ា"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ការប្រើប្រាស់កម្មវិធីថ្មីៗនេះ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"មើលការចូលប្រើនាពេលថ្មីៗនេះ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index db1b35d..6c0f833 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ಬೇರೊಂದು ಸಾಧನದಿಂದ ಸಿಸ್ಟಮ್ ಭಾಷೆಯ ಬದಲಾವಣೆಯನ್ನು ವಿನಂತಿಸಲಾಗಿದೆ"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ಭಾಷೆಯನ್ನು ಬದಲಾಯಿಸಿ"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ಪ್ರಸ್ತುತ ಭಾಷೆಯನ್ನೇ ಇರಿಸಿ"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ವೈ-ಫೈ ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ಈ ನೆಟ್‌ವರ್ಕ್‌ನಲ್ಲಿ ವೈರ್‌ಲೆಸ್ ಡೀಬಗ್ ಮಾಡುವಿಕೆಯನ್ನು ಅನುಮತಿಸಬೇಕೆ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ನೆಟ್‌ವರ್ಕ್ ಹೆಸರು (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nವೈ-ಫೈ ವಿಳಾಸ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ಈ ನೆಟ್‌ವರ್ಕ್‌ನಲ್ಲಿ ಅನುಮತಿಸಿ"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ಪಾಸ್‌ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ಹಲವಾರು ತಪ್ಪು ಪ್ರಯತ್ನಗಳು.\nಮತ್ತೆ <xliff:g id="NUMBER">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ತುರ್ತು"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> ಪ್ರಯತ್ನಗಳು."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ನಿಮ್ಮ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"ಮುಂದಿನ ಪ್ರಯತ್ನದಲ್ಲಿ ನೀವು ತಪ್ಪಾದ ಪ್ಯಾಟರ್ನ್‌ ನಮೂದಿಸಿದರೆ, ಈ ಸಾಧನದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"ನೀವು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುತ್ತಿರುವಾಗ ಅಥವಾ ಕ್ಯಾಸ್ಟ್ ಮಾಡುತ್ತಿರುವಾಗ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಕಾಣಿಸುವ ಅಥವಾ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುತ್ತಿರುವಾಗ ಅಥವಾ ಕ್ಯಾಸ್ಟ್ ಮಾಡುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್‌ನಲ್ಲಿ ತೋರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ಪ್ರಾರಂಭಿಸಿ"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಈ ಆಯ್ಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದೆ"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"ಕ್ಯಾಸ್ಟ್ ಮಾಡಲು ಪ್ರಾರಂಭಿಸಬೇಕೇ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"ನೀವು ಕ್ಯಾಸ್ಟ್ ಮಾಡುವಾಗ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಕಾಣಿಸುವ ಅಥವಾ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ Android ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಕ್ಯಾಸ್ಟ್ ಮಾಡುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್‌ನಲ್ಲಿ ತೋರಿಸುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡುವ ಯಾವುದೇ ವಿಷಯಕ್ಕೆ Android ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಹಾಗೂ ಆಡಿಯೊ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಕುರಿತು ಜಾಗರೂಕರಾಗಿರಿ."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ನಿಮ್ಮ ಮಾತನ್ನು ಆಲಿಸುತ್ತಿದೆ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
     <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ಮೈಕ್ರೊಫೋನ್ ಮತ್ತು ಕ್ಯಾಮರಾ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ ಬಳಕೆ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ಇತ್ತೀಚಿನ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ನೋಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 97271c5..491c4e4 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"다른 기기에서 시스템 언어 변경을 요청함"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"언어 변경"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"현재 언어 유지"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi 공유"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"이 네트워크에서 무선 디버깅을 허용하시겠습니까?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"네트워크 이름(SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi 주소(BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"이 네트워크에서 항상 허용"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"잘못된 패턴"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"잘못된 비밀번호"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"잘못된 시도 횟수가 너무 많습니다.\n<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도하세요."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"긴급"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"다시 시도하세요. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>회 중 <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>번째 시도입니다."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"데이터가 삭제됨"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"다음번 시도에서 잘못된 패턴을 입력하면 이 기기의 데이터가 삭제됩니다."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"공유, 녹화 또는 전송 중에 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 앱이 화면에 표시되거나 기기에서 재생되는 모든 항목에 액세스할 수 있습니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"앱을 공유, 녹화 또는 전송할 때는 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 앱이 해당 앱에 표시되거나 재생되는 모든 항목에 액세스할 수 있으므로 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"시작"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 이 옵션을 사용 중지했습니다."</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"전송을 시작하시겠습니까?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"전송 중에는 Android가 화면에 표시되거나 기기에서 재생되는 모든 항목에 액세스할 수 있습니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"앱을 전송할 때 Android가 해당 앱에 표시되거나 재생되는 모든 항목에 액세스할 수 있으므로 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"어시스턴트가 대기 중임"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string>
     <string name="install_app" msgid="5066668100199613936">"앱 설치"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"마이크 및 카메라"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"최근 앱 사용"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"최근 액세스 보기"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index db47e39..77e4e9c 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Система тилин өзгөртүү сурамы башка түзмөктөн жөнөтүлдү"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Тилди өзгөртүү"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Учурдагы тилди калтыруу"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi\'ды бөлүшүү"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Ушул тармакта мүчүлүштүктөрдү Wi-Fi аркылуу аныктоого уруксат бересизби?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Тармактын аталышы (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi дареги (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Бул тармакта ар дайым уруксат берилсин"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Графикалык ачкыч туура эмес"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Сырсөз туура эмес"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Өтө көп жолу жаңылдыңыз.\n<xliff:g id="NUMBER">%d</xliff:g> секунддан кийин кайра кайталаңыз."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Шашылыш чалуу"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Кайра кайталаңыз. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> аракеттен <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> аракет калды."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Акыркы аракет калды"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Эгер графикалык ачкычты кийинки жолу туура эмес киргизсеңиз, бул түзмөктүн маалыматы өчүрүлөт."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Бөлүшүп, жаздырып же тышкы экранга чыгарып жатканда <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосу экраныңыздагы бардык маалыматты же түзмөктө ойнотулуп жаткан нерселерди көрө алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Колдонмону бөлүшүп, жаздырып же тышкы экранга чыгарганда <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосу ал колдонмодо көрсөтүлүп жана ойнотулуп жаткан нерселерди көрө алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Баштоо"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> бул параметрди өчүрүп койду"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Тышкы экранга чыгаруу башталсынбы?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Тышкы экранга чыгарганда Android экраныңызда көрүнүп жана түзмөктө ойнотулуп жаткан нерселерди көрө алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Колдонмону тышкы экранга чыгарганда Android ал колдонмодо көрсөтүлүп жана ойнотулуп жаткан нерселерди көрө алат. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Жардамчы иштетилди"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string>
     <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон жана камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Жакында колдонмолордо иштетилген"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Акыркы пайдалануусун көрүү"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index ff08be1..ec17441 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ມີການຮ້ອງຂໍໃຫ້ປ່ຽນພາສາລະບົບໂດຍອຸປະກອນອື່ນ"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ປ່ຽນພາສາ"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ໃຊ້ພາສາປັດຈຸບັນ"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ແບ່ງປັນ Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ອະນຸຍາດການດີບັກໄຮ້ສາຍຢູ່ເຄືອຂ່າຍນີ້ບໍ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ຊື່ເຄືອຂ່າຍ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nທີ່ຢູ່ Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ອະນຸຍາດຕະຫຼອດຢູ່ເຄືອຂ່າຍນີ້"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ຮູບແບບບໍ່ຖືກຕ້ອງ"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ມີ​ຄວາມ​ພະ​ຍາ​ຍາມ​ບໍ່​ຖືກ​ຕ້ອງ​ຫຼາຍ​ເທື່ອ​ເກີນ​ໄປ.\nກະລຸນາລອງ​ໃໝ່​ອີກ​ໃນ <xliff:g id="NUMBER">%d</xliff:g> ​ວິ​ນາ​ທີ."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ສຸກເສີນ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ກະລຸນາລອງໃໝ່. ຄວາມພະຍາຍາມເທື່ອທີ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ຂໍ້ມູນຂອງທ່ານຈະຖືກລຶບອອກ"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"ຫາກທ່ານໃສ່ຣູບແບບຜິດໃນຄວາມພະຍາຍາມເທື່ອຕໍ່ໄປ, ອຸປະກອນນີ້ຈະຖືກລຶບຂໍ້ມູນອອກ."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"ເມື່ອທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກສິ່ງທີ່ປາກົດຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"ເມື່ອທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານແອັບ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ຈະມີສິດເຂົ້າເຖິງທຸກສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ແອັບດັ່ງກ່າວ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ເລີ່ມ"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ປິດການນຳໃຊ້ຕົວເລືອກນີ້ແລ້ວ"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"ເລີ່ມການສົ່ງສັນຍານບໍ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"ເມື່ອທ່ານກຳລັງສົ່ງສັນຍານ, Android ຈະມີສິດເຂົ້າເຖິງທຸກສິ່ງທີ່ປາກົດຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"ເມື່ອທ່ານກຳລັງສົ່ງສັນຍານແອັບ, Android ຈະມີສິດເຂົ້າເຖິງທຸກສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ແອັບດັ່ງກ່າວ. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"ການເອີ້ນໃຊ້ຜູ້ຊ່ວຍເປີດຢູ່"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
     <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ໄມໂຄຣໂຟນ ແລະ ກ້ອງຖ່າຍຮູບ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ການໃຊ້ແອັບຫຼ້າສຸດ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ເບິ່ງສິດເຂົ້າເຖິງຫຼ້າສຸດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index d3fc063..e418e18 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Užklausą dėl sistemos kalbos pakeitimo pateikė kitas įrenginys"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Keisti kalbą"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Palikti dabartinę kalbą"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Bendrinti „Wi‑Fi“"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Leisti belaidžio ryšio derinimą prisijungus prie šio tinklo?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Tinklo pavadinimas (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\n„Wi‑Fi“ adresas (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Visada leisti naudojant šį tinklą"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Netinkamas atrakinimo piešinys"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Netinkamas slaptažodis"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Per daug klaidingų bandymų.\nBandykite dar kartą po <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Skamb. pagalbos nr."</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Bandykite dar kartą. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> bandymas iš <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Duomenys bus ištrinti"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Jei kitu bandymu nupiešite netinkamą atrakinimo piešinį, šio įrenginio duomenys bus ištrinti."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kai bendrinate, įrašote ar perduodate turinį, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ gali pasiekti viską, kas rodoma ekrane ar leidžiama įrenginyje. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kai bendrinate, įrašote ar perduodate programą, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ gali pasiekti viską, kas rodoma ar leidžiama programoje. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Pradėti"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Programoje „<xliff:g id="APP_NAME">%1$s</xliff:g>“ ši parinktis išjungta"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Pradėti perdavimą?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kai perduodate turinį, „Android“ gali pasiekti viską, kas rodoma ekrane ar leidžiama įrenginyje. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kai perduodate programą, „Android“ gali pasiekti viską, kas rodoma ar leidžiama toje programoje. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Padėjėjas klauso"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string>
     <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofonas ir fotoaparatas"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Pastarasis programos naudojimas"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Žr. pastarąją prieigą"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c577473..4b5fea3 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Sistēmas valodas maiņu pieprasīja cita ierīce."</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Mainīt valodu"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Paturēt pašreizējo valodu"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Koplietot Wi-Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Vai atļaut bezvadu atkļūdošanu šajā tīklā?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Tīkla nosaukums (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi adrese (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Vienmēr atļaut šajā tīklā"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Nepareiza kombinācija"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Nepareiza parole"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Pārāk daudz neveiksmīgu mēģinājumu.\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER">%d</xliff:g> sekundēm."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Ārkārtas situācija"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Mēģiniet vēlreiz (<xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. mēģinājums no <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>)."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Jūsu dati tiks dzēsti"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ja nākamajā mēģinājumā ievadīsiet nepareizu kombināciju, dati šajā ierīcē tiks dzēsti."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kopīgošanas, ierakstīšanas vai apraides laikā <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> var piekļūt visam, kas tiek rādīts jūsu ekrānā vai atskaņots jūsu ierīcē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Lietotnes kopīgošanas, ierakstīšanas vai apraides laikā <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> var piekļūt visam, kas tiek rādīts vai atskaņots attiecīgajā lietotnē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Sākt"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> tika atspējota šī opcija"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Vai sākt apraidi?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Apraides laikā Android var piekļūt visam, kas tiek rādīts jūsu ekrānā vai atskaņots jūsu ierīcē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Lietotnes apraides laikā Android var piekļūt visam, kas tiek rādīts vai atskaņots attiecīgajā lietotnē. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistents klausās"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string>
     <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofons un kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nesen izmantoja lietotnes"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Skatīt neseno piekļuvi"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 9d92b5f..80aa943 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Побарана е промена на системскиот јазик од друг уред"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Промени го јазикот"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Зачувај го тековниот јазик"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Сподели Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Да се дозволи безжично отстранување грешки на мрежава?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Име на мрежата (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi адреса (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Секогаш дозволувај на оваа мрежа"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Погрешна шема"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Погрешна лозинка"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Премногу погрешни обиди.\nОбидете се повторно за <xliff:g id="NUMBER">%d</xliff:g>секунди."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Итен случај"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Обидете се повторно. Обид <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> од <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Податоците ќе се избришат"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ако внесете погрешна шема при следниот обид, податоците на уредов ќе се избришат."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Кога споделувате, снимате или емитувате, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има пристап до сѐ што е видливо на вашиот екран или пуштено на вашиот уред. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Кога споделувате, снимате или емитувате апликација, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има пристап до сѐ што се прикажува или пушта на таа апликација. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Започни"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ја оневозможи опцијава"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Да се започне со емитување?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Кога емитувате, Android има пристап до сѐ што е видливо на вашиот екран или пуштено на вашиот уред. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Додека емитувате апликација, Android има пристап до сѐ што се прикажува или пушта на таа апликација. Затоа, бидете внимателни со лозинки, детали за плаќање, пораки фотографии и аудио и видео."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Вниманието на „Помошникот“ е вклучено"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Неодамнешно користење на апликација"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Видете го скорешниот пристап"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index a33eb4b..021607d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"സിസ്റ്റത്തിന്റെ ഭാഷ മാറ്റാൻ മറ്റൊരു ഉപകരണം അഭ്യർത്ഥിച്ചു"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ഭാഷ മാറ്റുക"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"നിലവിലെ ഭാഷ നിലനിർത്തുക"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"വൈഫൈ പങ്കിടുക"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ഈ നെറ്റ്‌വർക്കിൽ വയർലെസ് ഡീബഗ്ഗിംഗ് അനുവദിക്കണോ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"നെറ്റ്‌വർക്കിന്റെ പേര് (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nവൈഫൈ വിലാസം (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ഈ നെറ്റ്‌വർക്കിൽ എപ്പോഴും അനുവദിക്കുക"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"പാറ്റേൺ തെറ്റാണ്"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"പാസ്‌വേഡ് തെറ്റാണ്"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"നിരവധി തെറ്റായ ശ്രമങ്ങൾ. \n<xliff:g id="NUMBER">%d</xliff:g> സെക്കൻഡിൽ വീണ്ടും ശ്രമിക്കുക."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"അടിയന്തരം"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"വീണ്ടും ശ്രമിക്കുക. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> ശ്രമങ്ങളിൽ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> ശ്രമം."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"നിങ്ങളുടെ ഡാറ്റ ഇല്ലാതാക്കപ്പെടും"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"അടുത്ത തവണയും നിങ്ങൾ തെറ്റായ പാറ്റേൺ നൽകിയാൽ, ഈ ഉപകരണത്തിലെ ഡാറ്റ ഇല്ലാതാക്കപ്പെടും."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"പങ്കിടുമ്പോൾ, റെക്കോർഡ് ചെയ്യുമ്പോൾ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യുമ്പോൾ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ഉപകരണത്തിൽ പ്ലേ ചെയ്യുന്നതോ ആയ ഏത് കാര്യത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"ഒരു ആപ്പ് പങ്കിടുമ്പോൾ, റെക്കോർഡ് ചെയ്യുമ്പോൾ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യുമ്പോൾ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് ആ ആപ്പിൽ കാണിക്കുന്ന അല്ലെങ്കിൽ പ്ലേ ചെയ്യുന്ന എല്ലാത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ആരംഭിക്കുക"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ഈ ഓപ്‌ഷൻ പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"കാസ്റ്റ് ചെയ്യാൻ ആരംഭിക്കണോ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"നിങ്ങൾ കാസ്റ്റ് ചെയ്യുമ്പോൾ, Android-ന് സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ഉപകരണത്തിൽ പ്ലേ ചെയ്യുന്നതോ ആയ ഏത് കാര്യത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"നിങ്ങൾ ഒരു ആപ്പ് കാസ്റ്റ് ചെയ്യുമ്പോൾ, Android-ന് ആ ആപ്പിൽ കാണിക്കുന്നതോ പ്ലേ ചെയ്യുന്നതോ ആയ എല്ലാത്തിലേക്കും ആക്സസ് ഉണ്ട്. അതിനാൽ പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങൾ നൽകുമ്പോൾ സൂക്ഷിക്കുക."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant സജീവമാണ്"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string>
     <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"മൈക്രോഫോണും ക്യാമറയും"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"അടുത്തിടെയുള്ള ആപ്പ് ഉപയോഗം"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"അടുത്തിടെയുള്ള ആക്‌സസ് കാണുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index da9d794..9c7cf8b 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Өөр төхөөрөмжөөс системийн хэлийг өөрчлөх хүсэлт тавьсан"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Хэл солих"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Одоогийн хэлээр байлгах"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi-г хуваалцах"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Энэ сүлжээн дээр wireless debugging-г зөвшөөрөх үү?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Сүлжээний нэр (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi хаяг (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Энэ сүлжээн дээр үргэлж зөвшөөрөх"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Хээ буруу байна"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Нууц үг буруу байна"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Хэт олон удаа буруу оруулсан байна.\n<xliff:g id="NUMBER">%d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Яаралтай тусламж"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Дахин оролдоно уу. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>-с <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> оролдлого үлдлээ."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Таны өгөгдлийг устгах болно"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Та дараагийн оролдлогоор буруу хээ оруулбал энэ төхөөрөмжийн өгөгдлийг устгах болно."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Таныг хуваалцаж, бичиж эсвэл дамжуулж байх үед <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь таны дэлгэцэд харагдаж буй зүйл эсвэл төхөөрөмжид тань тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн мэдээлэл, мессеж, зураг, аудио болон видео зэрэг зүйлд болгоомжтой хандаарай."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Таныг хуваалцаж, бичлэг хийж эсвэл апп дамжуулж байх үед <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь тухайн аппад харуулсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио болон видео зэрэг бусад зүйлд болгоомжтой хандаарай."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Эхлүүлэх"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> энэ сонголтыг идэвхгүй болгосон"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Дамжуулж эхлэх үү?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Таныг дамжуулж байх үед Android таны дэлгэцэд харагдаж буй эсвэл төхөөрөмжид тань тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн мэдээлэл, мессеж, зураг, аудио болон видео зэрэг зүйлд болгоомжтой хандаарай."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Таныг апп дамжуулж байх үед Android тухайн аппад харуулсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн мэдээлэл, мессеж, зураг, аудио болон видео зэрэг зүйлд болгоомжтой хандаарай."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Туслах анхаарлаа хандуулж байна"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string>
     <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон болон камер"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Аппын саяхны ашиглалт"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Саяхны хандалтыг харах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5fcf947..72c5cb6 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"दुसऱ्या डिव्हाइसद्वारे सिस्टीमची भाषा बदलण्याची विनंती केली गेली"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"भाषा बदला"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"सध्याची भाषा ठेवा"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"वाय-फाय शेअर करा"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"या नेटवर्कवर वायरलेस डीबगिंग करण्यासाठी अनुमती द्यायची का?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्कचे नाव (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nवाय-फाय ॲड्रेस (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"या नेटवर्कवर नेहमी अनुमती द्या"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"चुकीचा पॅटर्न"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"चुकीचा पासवर्ड"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"बरेच चुकीचे प्रयत्न. \n <xliff:g id="NUMBER">%d</xliff:g> सेकंदांमध्‍ये पुन्हा प्रयत्न करा."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"आणीबाणी"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"पुन्हा प्रयत्न करा. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> पैकी <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> प्रयत्न."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"तुमचा डेटा हटवला जाईल"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"तुम्‍ही पुढील प्रयत्‍नात चुकीचा पॅटर्न एंटर केल्यास, या डिव्‍हाइसचा डेटा हटवला जाईल."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"तुम्ही शेअर, रेकॉर्ड किंवा कास्ट करत असताना, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ला तुमच्या स्क्रीनवर दाखवलेल्या किंवा डिव्हाइसवर प्ले केलेल्या कोणत्याही गोष्टीचा अ‍ॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"तुम्ही एखादे अ‍ॅप शेअर, रेकॉर्ड किंवा कास्ट करत असताना, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ला त्या अ‍ॅपवर दाखवलेल्या किंवा प्ले केलेल्या कोणत्याही गोष्टीचा अ‍ॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"सुरुवात करा"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा पर्याय बंद केला आहे"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"कास्ट करणे सुरू करायचे आहे का?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"तुम्ही कास्ट करत असताना, Android ला तुमच्या स्क्रीनवर दाखवलेल्या किंवा डिव्हाइसवर प्ले केलेल्या कोणत्याही गोष्टीचा अ‍ॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"तुम्ही एखादे अ‍ॅप कास्ट करत असताना, Android ला त्या अ‍ॅपवर दाखवलेल्या किंवा प्ले केलेल्या कोणत्याही गोष्टीचा अ‍ॅक्सेस असतो. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant चे लक्ष हे आता अ‍ॅक्टिव्ह आहे"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अ‍ॅप सेट करा"</string>
     <string name="install_app" msgid="5066668100199613936">"अ‍ॅप इंस्टॉल करा"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"मायक्रोफोन आणि कॅमेरा"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"अलीकडील अ‍ॅप वापर"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"अलीकडील अ‍ॅक्सेस पहा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index de88987..fd4e6b5 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Permintaan pertukaran bahasa sistem oleh peranti lain"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Tukar bahasa"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Kekalkan bahasa semasa"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Kongsi Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Benarkan penyahpepijatan wayarles pada rangkaian ini?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nama Rangkaian (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAlamat Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Sentiasa benarkan pada rangkaian ini"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Corak salah"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Kata laluan salah"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Terlalu banyak percubaan yang salah.\nCuba lagi dalam masa <xliff:g id="NUMBER">%d</xliff:g> saat."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Kecemasan"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Cuba lagi. Percubaan <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> daripada <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Data anda akan dipadamkan"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Jika anda memasukkan corak yang salah pada percubaan seterusnya, data peranti ini akan dipadamkan."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Apabila anda membuat perkongsian, rakaman atau penghantaran, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> boleh mengakses apa-apa sahaja yang boleh dilihat pada skrin anda atau dimainkan pada peranti anda. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Apabila anda berkongsi, merakam atau menghantar apl, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> boleh mengakses apa-apa sahaja yang ditunjukan atau dimainkan pada apl tersebut. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Mula"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah melumpuhkan pilihan ini"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Mulakan penghantaran?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Apabila anda membuat penghantaran, Android boleh mengakses apa-apa sahaja yang boleh dilihat pada skrin anda atau dimainkan pada peranti anda. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Apabila anda menghantar apl, Android boleh mengakses apa-apa sahaja yang ditunjukan atau dimainkan pada apl itu. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Perhatian pembantu dihidupkan"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string>
     <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"Dayakan paparan"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon &amp; Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Penggunaan apl terbaharu"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Lihat akses terbaharu"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 1f54ef6..5d249de 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"စက်နောက်တစ်ခုက စနစ်၏ ဘာသာစကားပြောင်းရန် တောင်းဆိုထားသည်"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ဘာသာစကားပြောင်းရန်"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"လက်ရှိဘာသာစကားဆက်သုံးရန်"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi မျှဝေရန်"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ဤကွန်ရက်တွင် ကြိုးမဲ့ အမှားရှာပြင်ခြင်းကို ခွင့်ပြုမလား။"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ကွန်ရက်အမည် (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi လိပ်စာ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ဤကွန်ရက်ကို အမြဲခွင့်ပြုပါ"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ပုံစံ မှားနေသည်"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"စကားဝှက် မှားနေသည်"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"မှားသည့် အကြိမ် အရေအတွက် အလွန်များသည်။\n<xliff:g id="NUMBER">%d</xliff:g>စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"အရေးပေါ်"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ထပ်စမ်းကြည့်ပါ။ <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> ကြိမ်အနက်မှ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> ကြိမ် ဖြစ်သည်။"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"သင်၏ဒေတာများ ပျက်သွားပါလိမ့်မည်"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"မှားယွင်းသည့် ပုံစံကို နောက်တစ်ကြိမ်ထည့်သွင်းပါက ဤစက်ပစ္စည်းပေါ်ရှိ ဒေတာများကို ဖျက်လိုက်ပါမည်။"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"မျှဝေ၊ ရုပ်သံဖမ်း (သို့) ကာစ်လုပ်သည့်အခါ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် သင့်ဖန်သားပြင်ရှိ မြင်နိုင်သည့် (သို့) သင့်စက်တွင် ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"အက်ပ်တစ်ခုဖြင့် မျှဝေ၊ ရုပ်သံဖမ်း (သို့) ကာစ်လုပ်သည့်အခါ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် ယင်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့အရာများကို ဂရုစိုက်ပါ။"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"စတင်ရန်"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် ဤရွေးစရာကို ပိတ်ထားသည်"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"ကာစ်လုပ်ခြင်း စမလား။"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"ကာစ်လုပ်သည့်အခါ Android သည် သင့်ဖန်သားပြင်ရှိ မြင်နိုင်သည့် (သို့) သင့်စက်တွင် ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"အက်ပ်တစ်ခုကို ကာစ်လုပ်သည့်အခါ Android သည် ယင်းအက်ပ်တွင် ပြထားသည့် (သို့) ဖွင့်ထားသည့် အရာအားလုံးကို တွေ့နိုင်သည်။ ထို့ကြောင့် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant နားထောင်နေသည်"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string>
     <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"မိုက်ခရိုဖုန်းနှင့် ကင်မရာ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"လတ်တလော အက်ပ်အသုံးပြုမှု"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"လတ်တလောအသုံးပြုမှုကို ကြည့်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 54a5341..1784675 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Bytte av systemspråk er forespurt av en annen enhet"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Bytt språk"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Behold gjeldende språk"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Del wifi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Vil du tillate trådløs feilsøking på dette nettverket?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nettverksnavn (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adresse (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Tillat alltid på dette nettverket"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Feil mønster"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Feil passord"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"For mange ugyldige forsøk.\nPrøv på nytt om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Nødssituasjon"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Prøv på nytt. Forsøk <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> av <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Dataene dine blir slettet"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Hvis du oppgir feil mønster på neste forsøk, slettes dataene på denne enheten."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Når du deler, tar opp eller caster noe, har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tilgang til alt som vises på skjermen eller spilles av på enheten. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Når du deler, tar opp eller caster en app, har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tilgang til alt som vises eller spilles av i den aktuelle appen. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Begynn"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> har deaktivert dette alternativet"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Vil du begynne å caste?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Når du caster, har Android tilgang til alt som vises på skjermen eller spilles av på enheten. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Når du caster en app, har Android tilgang til alt som vises eller spilles av i den aktuelle appen. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistentoppmerksomhet er på"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string>
     <string name="install_app" msgid="5066668100199613936">"Installer appen"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon og kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nylig appbruk"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se nylig tilgang"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 29b5098..94ac4b7 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"अर्को डिभाइसले सिस्टमको भाषा परिवर्तन गर्न अनुरोध गरेको छ"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"भाषा परिवर्तन गर्नुहोस्"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"अहिलेको भाषा राख्नुहोस्"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi सेयर गर्नुहोस्"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"यस नेटवर्कमा वायरलेस डिबगिङ सेवा प्रयोग गर्न दिने हो?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"नेटवर्कको नाम (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi ठेगाना (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"यस नेटवर्कमा सधैँ अनुमति दिइयोस्"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"प्याटर्न मिलेन"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"पासवर्ड मिलेन"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"अत्यन्तै धेरै पटक गलत प्रयास गरिए। \n <xliff:g id="NUMBER">%d</xliff:g>सेकेन्ड पछि पुनः प्रयास गर्नुहोस्।"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"आपत्कालीन"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"फेरि प्रयास गर्नुहोस्। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> मध्ये <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> प्रयास।"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"तपाईंको डेटा मेटाइने छ"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"तपाईंले अर्को पटक पनि गलत ढाँचा प्रविष्टि गर्नुभयो भने यो डिभाइसको डेटा मेटाइने छ।"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"तपाईंले सेयर गर्दा, रेकर्ड गर्दा वा कास्ट गर्दा <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देखिने वा डिभाइसमा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"तपाईंले कुनै एप सेयर गर्दा, रेकर्ड गर्दा वा कास्ट गर्दा <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले उक्त एपमा देखाइने वा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"सुरु गर्नुहोस्"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले यो विकल्प अफ गर्नुभएको छ"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"कास्ट गर्न थाल्ने हो?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"तपाईंले कास्ट गर्दा Android ले तपाईंको स्क्रिनमा देखिने वा डिभाइसमा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"तपाईंले कुनै एप कास्ट गर्दा Android ले उक्त एपमा देखाइने वा प्ले गरिने सबै कुरा हेर्न तथा प्रयोग गर्न सक्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"सहायकले सुनिरहेको छ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string>
     <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"माइक्रोफोन तथा क्यामेरा"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"एपको हालसालैको प्रयोग"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"हालसालै एक्सेस गर्ने एप हेर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 5799c35..f15eda0 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Wijziging van systeemtaal aangevraagd door een ander apparaat"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Taal wijzigen"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Huidige taal houden"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wifi delen"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Draadloze foutopsporing toestaan in dit netwerk?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Netwerknaam (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWifi-adres (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Altijd toestaan in dit netwerk"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Onjuist patroon"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Onjuist wachtwoord"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Te veel onjuiste pogingen.\nProbeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Noodgeval"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Probeer het opnieuw. Poging <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> van <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Je gegevens worden verwijderd"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Als je bij de volgende poging een onjuist patroon opgeeft, worden de gegevens van dit apparaat verwijderd."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Als je deelt, opneemt of cast, heeft <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot alles dat zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Als je deelt, opneemt of cast, heeft <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot alles dat wordt getoond of afgespeeld in die app. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Starten"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Voor <xliff:g id="APP_NAME">%1$s</xliff:g> staat deze optie uit"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Casten starten?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Als je cast, heeft Android toegang tot alles dat zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Als je een app cast, heeft Android toegang tot alles dat zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent-aandacht aan"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
     <string name="install_app" msgid="5066668100199613936">"App installeren"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfoon en camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Recent app-gebruik"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Recente toegang bekijken"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 68acfc0..8e34628 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ଅନ୍ୟ ଏକ ଡିଭାଇସ ଦ୍ୱାରା ସିଷ୍ଟମ ଭାଷା ପରିବର୍ତ୍ତନ ପାଇଁ ଅନୁରୋଧ କରାଯାଇଛି"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ଭାଷା ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ବର୍ତ୍ତମାନର ଭାଷା ରଖନ୍ତୁ"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ୱାଇ-ଫାଇ ସେୟାର କରନ୍ତୁ"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ଏହି ନେଟୱାର୍କରେ ୱାୟାରଲେସ୍ ଡିବଗିଂ ପାଇଁ ଅନୁମତି ଦେବେ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ନେଟୱାର୍କ ନାମ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nୱାଇଫାଇ ଠିକଣା (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ସର୍ବଦା ଏହି ନେଟୱାର୍କରେ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ଭୁଲ ପାଟର୍ନ"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ଭୁଲ ପାସ୍‌ୱାର୍ଡ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ଅନେକ ଥର ଭୁଲ ଚେଷ୍ଟା। \n <xliff:g id="NUMBER">%d</xliff:g>ସେକେଣ୍ଡରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ଜରୁରୀକାଳୀନ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>ଟିରୁ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>ଟି ପ୍ରଚେଷ୍ଟା।"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ଆପଣଙ୍କ ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"ଆପଣ ପରବର୍ତ୍ତୀ ପ୍ରଚେଷ୍ଟାରେ ଏକ ଭୁଲ ପାଟର୍ନ ପ୍ରବେଶ କଲେ, ଏହି ଡିଭାଇସର ଡାଟାକୁ ଡିଲିଟ୍ କରିଦିଆଯିବ।"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"ଆପଣ ସେୟାର, ରେକର୍ଡ କିମ୍ବା କାଷ୍ଟ କରିବା ସମୟରେ, ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ଆପଣଙ୍କ ଡିଭାଇସରେ ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"ଆପଣ ଏକ ଆପ ସେୟାର, ରେକର୍ଡ କିମ୍ବା କାଷ୍ଟ କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଏହି ବିକଳ୍ପକୁ ଅକ୍ଷମ କରିଛି"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"କାଷ୍ଟିଂ ଆରମ୍ଭ କରିବେ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"ଆପଣ କାଷ୍ଟ କରିବା ସମୟରେ, ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ଆପଣଙ୍କ ଡିଭାଇସରେ ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ Androidର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"ଆପଣ ଏକ ଆପ କାଷ୍ଟ କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ Androidର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ଆଟେନସନ ଚାଲୁ ଅଛି"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string>
     <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ମାଇକ୍ରୋଫୋନ ଏବଂ କେମେରା"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ବର୍ତ୍ତମାନର ଆପ ବ୍ୟବହାର"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ବର୍ତ୍ତମାନର ଆକ୍ସେସ ଦେଖନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index f8aac75..0861ca3 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ ਵੱਲੋਂ ਸਿਸਟਮ ਦੀ ਭਾਸ਼ਾ ਬਦਲਣ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਗਈ"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"ਭਾਸ਼ਾ ਬਦਲੋ"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ਮੌਜੂਦਾ ਭਾਸ਼ਾ ਰੱਖੋ"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"ਵਾਈ-ਫਾਈ ਸਾਂਝਾ ਕਰੋ"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ਕੀ ਇਸ ਨੈੱਟਵਰਕ \'ਤੇ ਵਾਇਰਲੈੱਸ ਡੀਬੱਗਿੰਗ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ਨੈੱਟਵਰਕ ਨਾਮ (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nਵਾਈ-ਫਾਈ ਪਤਾ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ਇਸ ਨੈੱਟਵਰਕ \'ਤੇ ਹਮੇਸ਼ਾਂ ਆਗਿਆ ਦਿਓ"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ਗਲਤ ਪੈਟਰਨ"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"ਗਲਤ ਪਾਸਵਰਡ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ਬਹੁਤ ਸਾਰੀਆਂ ਗ਼ਲਤ ਕੋਸ਼ਿਸ਼ਾਂ।\n<xliff:g id="NUMBER">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ਐਮਰਜੈਂਸੀ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ। <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> ਵਿੱਚੋਂ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> ਕੋਸ਼ਿਸ਼।"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ਤੁਹਾਡਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"ਜੇ ਤੁਸੀਂ ਅਗਲੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਕੋਈ ਗਲਤ ਪੈਟਰਨ ਦਾਖਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਇਸ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਂਝਾ ਕਰਨ, ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਕੋਲ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣ ਵਾਲੀ ਜਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਂਝਾ ਕਰਨ, ਰਿਕਾਰਡ ਕਰਨ, ਜਾਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਕੋਲ ਉਸ ਐਪ \'ਤੇ ਦਿਖਾਈ ਗਈ ਜਾਂ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਸੰਬੰਧੀ ਸਾਵਧਾਨ ਰਹੋ।"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ਸ਼ੁਰੂ ਕਰੋ"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੇ ਇਸ ਵਿਕਲਪ ਨੂੰ ਬੰਦ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"ਕੀ ਕਾਸਟ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, Android ਕੋਲ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਸਣ ਵਾਲੀ ਜਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"ਤੁਹਾਡੇ ਵੱਲੋਂ ਕਾਸਟ ਕਰਨ \'ਤੇ, Android ਕੋਲ ਉਸ ਐਪ \'ਤੇ ਦਿਖਾਈ ਗਈ ਜਾਂ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ ਤੱਕ ਪਹੁੰਚ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਸੰਬੰਧੀ ਸਾਵਧਾਨ ਰਹੋ।"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant ਧਿਆਨ ਸੁਵਿਧਾ ਨੂੰ ਚਾਲੂ ਹੈ"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string>
     <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਤੇ ਕੈਮਰਾ"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ਹਾਲ ਹੀ ਵਿੱਚ ਵਰਤੀ ਗਈ ਐਪ"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ਹਾਲੀਆ ਪਹੁੰਚ ਦੇਖੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ad63d1e..fff57db 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Inny użytkownik poprosił o zmianę języka systemu"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Zmień język"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Zachowaj bieżący język"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Udostępnij Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Zezwolić na debugowanie bezprzewodowe w tej sieci?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nazwa sieci (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdres Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Zawsze zezwalaj w tej sieci"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Nieprawidłowy wzór"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Nieprawidłowe hasło"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Zbyt wiele nieudanych prób.\n Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Połączenie alarmowe"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Spróbuj ponownie. Próba <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> z <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Dane zostaną usunięte"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Jeśli następnym razem podasz nieprawidłowy wzór, dane na urządzeniu zostaną usunięte."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Podczas udostępniania, nagrywania lub przesyłania treści aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ma dostęp do wszystkiego, co jest widoczne na ekranie lub odtwarzane na urządzeniu. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Podczas udostępniania, nagrywania lub przesyłania treści aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Rozpocznij"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ma wyłączoną tę opcję"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Rozpocząć przesyłanie?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Podczas przesyłania, Android ma dostęp do wszystkiego, co jest widoczne na ekranie lub odtwarzane na urządzeniu. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Podczas przesyłania treści z aplikacji Android ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asystent jest aktywny"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string>
     <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon i aparat"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Aplikacje korzystające w ostatnim czasie"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobacz ostatni dostęp"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 7f917c8..431863e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Mudança do idioma do sistema solicitada por outro dispositivo"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Alterar idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma atual"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Compartilhar Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração por Wi-Fi nesta rede?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço do Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Sempre permitir nesta rede"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Padrão incorreto"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Senha incorreta"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Excesso de tentativas incorretas.\nTente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergência"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Tente novamente. Tentativa <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Seus dados serão excluídos"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Se você informar um padrão incorreto na próxima tentativa, os dados deste dispositivo serão excluídos."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Quando você compartilha, grava ou transmite a tela, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis nela ou reproduzidas no dispositivo. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Quando você compartilha, grava ou transmite um app, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Início"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> desativou essa opção"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Começar a transmissão?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Quando você transmite a tela, o Android tem acesso a todas as informações visíveis nela ou reproduzidas no dispositivo. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Quando você transmite um app, o Android tem acesso a todas as informações visíveis ou reproduzidas nele. Tenha cuidado com senhas, detalhes de pagamento, mensagens fotos, áudios e vídeos."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Atenção do Assistente ativada"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente do app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consultar acessos recentes"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e455f01..1c0ff6b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Alteração do idioma do sistema solicitada por outro dispositivo"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Alterar idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma atual"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Partilhar Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração sem fios nesta rede?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permitir sempre nesta rede"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Padrão incorreto."</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Palavra-passe incorreta."</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Demasiadas tentativas incorretas.\nTente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergência"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Tente novamente. Tentativa <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Os seus dados serão eliminados"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Se introduzir um padrão incorreto na tentativa seguinte, os dados deste dispositivo serão eliminados."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Quando está a partilhar, gravar ou transmitir, a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a tudo o que está visível no seu ecrã ou é reproduzido no seu dispositivo. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Quando está a partilhar, gravar ou transmitir uma app, a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a tudo o que é apresentado ou reproduzido nessa app. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Iniciar"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> desativou esta opção"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Começar a transmitir?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Quando está a transmitir conteúdo, o Android tem acesso a tudo o que está visível no seu ecrã ou é reproduzido no seu dispositivo. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Quando está a transmitir uma app, o Android tem acesso a tudo o que é apresentado ou reproduzido nessa app. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Atenção do Assistente ativada"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"Ativar ecrã"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmara"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilização recente da app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ver acesso recente"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 7f917c8..431863e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Mudança do idioma do sistema solicitada por outro dispositivo"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Alterar idioma"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Manter idioma atual"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Compartilhar Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Permitir a depuração por Wi-Fi nesta rede?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome da rede (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nEndereço do Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Sempre permitir nesta rede"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Padrão incorreto"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Senha incorreta"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Excesso de tentativas incorretas.\nTente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergência"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Tente novamente. Tentativa <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> de <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Seus dados serão excluídos"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Se você informar um padrão incorreto na próxima tentativa, os dados deste dispositivo serão excluídos."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Quando você compartilha, grava ou transmite a tela, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis nela ou reproduzidas no dispositivo. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Quando você compartilha, grava ou transmite um app, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Início"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> desativou essa opção"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Começar a transmissão?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Quando você transmite a tela, o Android tem acesso a todas as informações visíveis nela ou reproduzidas no dispositivo. Portanto, tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Quando você transmite um app, o Android tem acesso a todas as informações visíveis ou reproduzidas nele. Tenha cuidado com senhas, detalhes de pagamento, mensagens fotos, áudios e vídeos."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Atenção do Assistente ativada"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfone e câmera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Uso recente do app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Consultar acessos recentes"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 844027a..513abc2 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Alt dispozitiv solicită schimbarea limbii de sistem"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Schimbă limba"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Păstrează limba actuală"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Permite accesul la Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Permiți remedierea erorilor wireless în această rețea?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Numele rețelei (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permite întotdeauna în această rețea"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Model greșit"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Parolă greșită"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Prea multe încercări incorecte.\nÎncearcă din nou peste <xliff:g id="NUMBER">%d</xliff:g> secunde."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Urgență"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Încearcă din nou. Încercarea <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> din <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Datele tale vor fi șterse"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Dacă la următoarea încercare introduci un model incorect, datele de pe acest dispozitiv vor fi șterse."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Când permiți accesul, înregistrezi sau proiectezi, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> are acces la orice este vizibil pe ecran sau se redă pe dispozitiv. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Când permiți accesul, înregistrezi sau proiectezi o aplicație, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> are acces la orice se afișează pe ecran sau se redă în aplicație. Prin urmare, ai grijă cu informații cum ar fi parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Începe"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> a dezactivat această opțiune"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Începi să proiectezi?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Când proiectezi, Android are acces la orice este vizibil pe ecran sau se redă pe dispozitiv. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Când proiectezi o aplicație, Android are acces la orice se afișează sau se redă în aplicație. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistentul este atent"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
     <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Microfon și cameră"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Utilizare recentă în aplicații"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Vezi accesarea recentă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9728103..694ccdf 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Получен запрос на изменение системного языка от другого устройства."</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Изменить язык"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Оставить текущий язык"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Поделиться Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Разрешить отладку по Wi-Fi в этой сети?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Название сети (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nMAC-адрес точки доступа (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Всегда разрешать отладку в этой сети"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Неверный графический ключ."</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Неверный пароль."</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Слишком много неудачных попыток.\nПовторите через <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Экстренный вызов"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Попробуйте ещё раз. Попытка <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> из <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Осталась одна попытка"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Если вы неправильно введете графический ключ ещё раз, с устройства будут удалены все данные."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Когда вы демонстрируете, транслируете экран или записываете видео с него, приложение \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" получает доступ ко всему, что видно или воспроизводится на устройстве. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Когда вы демонстрируете, записываете или транслируете экран приложения, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> получает доступ ко всему, что видно или воспроизводится в этом приложении. Будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Начать"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" отключило эту возможность"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Начать трансляцию?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Во время трансляции система Android получает доступ ко всему, что видно или воспроизводится на устройстве. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Когда вы транслируете экран приложения, система Android получает доступ ко всему, что видно или воспроизводится в нем. Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Ассистент готов слушать"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
     <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Недавнее использование приложениями"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Посмотреть недавний доступ"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 2424fe1..7ac474d 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"වෙනත් උපාංගයකින් පද්ධති භාෂාව වෙනස් කිරීම ඉල්ලා ඇත"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"භාෂාව වෙනස් කරන්න"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"වත්මන් භාෂාව තබා ගන්න"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi බෙදා ගන්න"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"මෙම ජාලයේ නොරැහැන් නිදොස්කරණය ඉඩ දෙන්නද?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ජාල නම (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi ලිපිනය (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"මෙම ජාලයේ සැමවිට ඉඩ දෙන්න"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"වැරදි රටාවකි"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"වැරදි මුරපදයකි"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"වැරදි උත්සාහයන් ගණන වැඩියි. තත්පර \n තත්පර <xliff:g id="NUMBER">%d</xliff:g>කින් නැවත උත්සාහ කරන්න."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"හදිසි අවස්ථාව"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"නැවත උත්සාහ කරන්න. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>කින් <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> උත්සාහය."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ඔබේ දත්ත මකනු ඇත"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"ඔබ ඊළඟ උත්සාහයේදී වැරදි රටාවක් ඇතුළු කළහොත්, මෙම උපාංගයෙහි දත්ත මකනු ඇත."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"ඔබ බෙදා ගන්නා විට, පටිගත කරන විට, හෝ විකාශනය කරන විට, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> හට ඔබේ තිරයේ පෙනෙන හෝ ඔබේ උපාංගයේ වාදනය වන ඕනෑම දෙයකට ප්‍රවේශය ඇත. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්‍රව්‍ය සහ දෘශ්‍ය වැනි දේවල් පිළිබඳ ප්‍රවේශම් වන්න."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"ඔබ යෙදුමක් බෙදා ගන්නා විට, පටිගත කරන විට හෝ විකාශය කරන විට, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> හට එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයකට ප්‍රවේශය ඇත. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්‍රව්‍ය සහ දෘශ්‍ය වැනි දේවල් පිළිබඳ ප්‍රවේශම් වන්න."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"අරඹන්න"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> මෙම විකල්පය අබල කර ඇත"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"විකාශය ආරම්භ කරන්න ද?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"ඔබ විකාශය කරන විට, Android හට ඔබේ තිරයේ පෙනෙන හෝ ඔබේ උපාංගයේ වාදනය වන ඕනෑම දෙයකට ප්‍රවේශය ඇත. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්‍රව්‍ය සහ දෘශ්‍ය වැනි දේවල් පිළිබඳ ප්‍රවේශම් වන්න."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"ඔබ යෙදුමක් විකාශය කරන විට, Android හට එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයකට ප්‍රවේශය ඇත. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවුඩ, ඡායාරූප, සහ ශ්‍රව්‍ය සහ දෘශ්‍ය වැනි දේවල් පිළිබඳ ප්‍රවේශම් වන්න."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"සහයක අවධානය යොමු කරයි"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string>
     <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"මයික්‍රොෆෝනය සහ කැමරාව"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"මෑත යෙදුම් භාවිතය"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"මෑත ප්‍රවේශය බලන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 4e1b46b..92813d0 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Zmenu jazyka systému vyžiadalo iné zariadenie"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Zmeniť jazyk"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Ponechať aktuálny jazyk"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Zdieľať Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Chcete povoliť bezdrôtové ladenie v tejto sieti?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Názov siete (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Vždy povoliť v tejto sieti"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Nesprávny vzor"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Nesprávne heslo"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Príliš veľa nesprávnych pokusov. \nSkúste to znova o <xliff:g id="NUMBER">%d</xliff:g> s."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Tieseň"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Skúste to znova. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. z <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> pokusov."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vaše dáta budú odstránené"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ak pri ďalšom pokuse zadáte nesprávny vzor, dáta tohto zariadenia budú odstránené."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Počas zdieľania, nahrávania alebo prenosu bude mať <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému, čo sa zobrazuje na obrazovke alebo prehráva v zariadení. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Počas zdieľania, nahrávania alebo prenosu v aplikácii bude mať <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému, čo sa v danej aplikácii zobrazuje alebo prehráva. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Začať"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> túto možnosť zakázala"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Chcete spustiť prenos?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Počas prenosu bude mať Android prístup k všetkému, čo sa zobrazuje na obrazovke alebo prehráva v zariadení. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Počas prenosu v aplikácii bude mať Android prístup k všetkému, čo sa v danej aplikácii zobrazuje alebo prehráva. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Pozornosť Asistenta je zapnutá"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string>
     <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofón a fotoaparát"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedávne využitie aplikácie"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Zobraziť nedávny prístup"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 89e9276..0650354 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Spremembo jezika sistema je zahtevala druga naprava."</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Spremeni jezik"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Obdrži trenutni jezik"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Delite omrežje Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Ali dovolite brezžično odpravljanje napak v tem omrežju?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Ime omrežja (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nNaslov omrežja Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Vedno dovoli v tem omrežju"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Napačen vzorec"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Napačno geslo"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Preveč napačnih poskusov.\nPoskusite znova čez <xliff:g id="NUMBER">%d</xliff:g> s."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Nujni primer"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Poskusite znova. Poskus <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> od <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Vaši podatki bodo izbrisani"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Če pri naslednjem poskusu vnesete napačen vzorec, bodo podatki v tej napravi izbrisani."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Pri deljenju, snemanju ali predvajanju ima aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dostop do vsega, kar je prikazano na zaslonu ali se predvaja v napravi. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Pri deljenju, snemanju ali predvajanju aplikacije ima aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dostop do vsega, kar je prikazano ali predvajano v tej aplikaciji, zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Začni"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogočila to možnost"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Želite začeti predvajati?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Pri predvajanju ima Android dostop do vsega, kar je prikazano na zaslonu ali se predvaja v napravi. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Pri predvajanju aplikacije ima Android dostop do vsega, kar je prikazano ali predvajano v tej aplikaciji, zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Zaznavanje pomočnika je vklopljeno."</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string>
     <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon in fotoaparat"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Nedavna uporaba v aplikacijah"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Ogled nedavnih dostopov"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 2c61054..08d3c55 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Një pajisje tjetër kërkoi ndryshimin e gjuhës së sistemit"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Ndrysho gjuhën"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mbaj gjuhën aktuale"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Ndaj Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Të lejohet korrigjimi përmes Wi-Fi në këtë rrjet?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Emri i rrjetit (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Lejo gjithmonë në këtë rrjet"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Motiv i gabuar"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Fjalëkalim i gabuar"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Shumë tentativa të pasakta.\nProvo përsëri brenda <xliff:g id="NUMBER">%d</xliff:g> sekondash."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Urgjencë"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Provo sërish. Tentativa <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> nga <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Të dhënat e tua do të fshihen"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Nëse fut një motiv të pasaktë në tentativën tjetër, të dhënat e kësaj pajisjeje do të fshihen."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kur ti ndan, regjistron ose transmeton, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në pajisjen tënde. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kur ti ndan, regjistron ose transmeton një aplikacion, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në atë aplikacion. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Nis"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> e ka çaktivizuar këtë opsion"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Të niset transmetimi?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kur ti transmeton, Android ka qasje te çdo gjë e dukshme në ekranin tënd ose që po luhet në pajisjen tënde. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kur ti transmeton një aplikacion, Android ka qasje te çdo gjë e dukshme ose që po luhet në atë aplikacion. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesës, mesazhet, fotografitë, si dhe audion dhe videon."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Vëmendja e \"Asistentit\" aktive"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string>
     <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofoni dhe kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Përdorimi i fundit i aplikacionit"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Shiko qasjen e fundit"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 7b208290..1856303 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Други уређај је затражио промену језика система"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Промени језик"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Задржи актуелни језик"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Дели WiFi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Желите да дозволите бежично отклањање грешака на овој мрежи?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Назив мреже (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi адреса (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Увек дозволи на овој мрежи"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Погрешан шаблон"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Погрешна лозинка"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Превише нетачних покушаја.\n Пробајте поново за <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Хитан случај"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Пробајте поново. <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>. покушај од <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Подаци ће се избрисати"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ако унесете нетачан шаблон при следећем покушају, избрисаћемо податке са овог уређаја."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Када делите, снимате или пребацујете, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има приступ комплетном садржају који је видљив на екрану или се пушта на уређају. Зато будите пажљиви са лозинкама, информацијама о плаћању, порукама, сликама и аудио и видео снимцима."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Када делите, снимате или пребацујете апликацију, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има приступ комплетном садржају који је видљив или се пушта у тој апликацији. Зато будите пажљиви са лозинкама, информацијама о плаћању, порукама, сликама и аудио и видео снимцима."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Покрени"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је онемогућила ову опцију"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Желите да започнете пребацивање?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Када пребацујете, Android има приступ комплетном садржају који је видљив на екрану или се пушта на уређају. Зато будите пажљиви са лозинкама, информацијама о плаћању, порукама, сликама и аудио и видео снимцима."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Када пребацујете апликацију, Android има приступ комплетном садржају који је видљив или се пушта у тој апликацији. Зато будите пажљиви са лозинкама, информацијама о плаћању, порукама, сликама и аудио и видео снимцима."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Помоћник је у активном стању"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string>
     <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Микрофон и камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Недавно користила апликација"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Прикажи недавни приступ"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0ebb778..76b6f1d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ändring av systemspråk har begärts av en annan enhet"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Ändra språk"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Behåll nuvarande språk"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Dela wifi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Vill du tillåta trådlös felsökning i det här nätverket?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Nätverksnamn (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi-adress (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Tillåt alltid i det här nätverket"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Fel mönster"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Fel lösenord"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"För många felaktiga försök.\nFörsök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Nödsituation"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Försök igen. Försök <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> av <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Din data raderas."</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Enhetens data raderas om du ritar fel mönster vid nästa försök."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"När du delar, spelar in eller castar har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> åtkomst till allt som visas på skärmen eller spelas upp på enheten. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton och ljud och video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"När du delar, spelar in eller castar en app har <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> åtkomst till allt som visas eller spelas upp i appen. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton och ljud och video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Börja"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inaktiverat alternativet"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Vill du börja casta?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"När du castar har Android åtkomst till allt som visas på skärmen eller spelas upp på enheten. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton och ljud och video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"När du castar en app har Android åtkomst till allt som visas eller spelas upp i appen. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton och ljud och video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistenten är aktiverad"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string>
     <string name="install_app" msgid="5066668100199613936">"Installera appen"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon och kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Senaste appanvändning"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Se senaste åtkomst"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 29d6405..1713544 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Mabadiliko ya lugha ya mfumo yameombwa na kifaa kingine"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Badilisha lugha"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Usibadilishe lugha ya sasa"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Shiriki Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Ungependa kuruhusu utatuzi usiotumia waya kwenye mtandao huu?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Jina la Mtandao (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAnwani ya Wi-Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Ruhusu kila wakati kwenye mtandao huu"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Mchoro si sahihi"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Nenosiri si sahihi"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Majaribio mengi mno yasiyo sahihi.\nJaribu tena baada ya sekunde <xliff:g id="NUMBER">%d</xliff:g>."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Simu za dharura"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Jaribu tena. Jaribio la <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> kati ya <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Data yako itafutwa"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Ukiweka mchoro usio sahihi utakapojaribu tena, data iliyo kwenye kifaa hiki itafutwa."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Unaposhiriki, kurekodi au kutuma, programu ya <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inaweza kufikia kitu chochote kitakachoonekana kwenye skrini yako au kuchezwa kwenye kifaa chako. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha na sauti na video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Unaposhiriki, kurekodi au kutuma programu, programu, programu ya <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inaweza kufikia kitu chochote kitakachoonekana au kuchezwa kwenye programu hiyo. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha na sauti na video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Anza"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> imezima chaguo hili"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Ungependa kuanza kutuma?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Unapotuma, Android inaweza kufikia kitu chochote kitakachoonekana kwenye skrini yako au kuchezwa kwenye kifaa chako. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha na sauti na video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Unapotuma programu, Android inaweza kufikia kitu chochote kitakachoonekana au kuchezwa kwenye programu hiyo. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha na sauti na video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Programu ya Mratibu imewashwa"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string>
     <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Maikrofoni na Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Matumizi ya programu hivi majuzi"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Angalia ufikiaji wa majuzi"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/bools.xml b/packages/SystemUI/res/values-sw600dp/bools.xml
index 05e38bd..d7ddf00 100644
--- a/packages/SystemUI/res/values-sw600dp/bools.xml
+++ b/packages/SystemUI/res/values-sw600dp/bools.xml
@@ -18,4 +18,12 @@
 <resources>
     <!-- Whether to show the user switcher in quick settings when only a single user is present. -->
     <bool name="qs_show_user_switcher_for_single_user">true</bool>
+
+    <!--  Do update bouncer constraints (port or land) on rotation.
+      Needed for bouncer refactor to use motion layout, because constraints should only be
+      changed on small screens. Only used when flag "lockscreen.enable_landscape" (b/293252410)
+      is enabled
+
+      False here so bouncers constraints are not updated when rotating on large screens -->
+    <bool name="update_bouncer_constraints">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 13e92e5..c0e4c3d 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"சிஸ்டம் மொழியை மாற்றும்படி வேறொரு சாதனம் கோருகிறது"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"மொழியை மாற்று"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"தற்போதைய மொழியை வைத்திரு"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"வைஃபையைப் பகிர்"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"இந்த நெட்வொர்க்கில் வைஃபை பிழைதிருத்தத்தை அனுமதிக்கவா?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"நெட்வொர்க் பெயர் (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nவைஃபை முகவரி (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"இந்த நெட்வொர்க்கில் எப்போதும் அனுமதி"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"தவறான பேட்டர்ன்"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"தவறான கடவுச்சொல்"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"பல தவறான முயற்சிகள்.\n<xliff:g id="NUMBER">%d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"அவசர அழைப்பு"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"மீண்டும் முயலவும். <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> முறை முயன்றுவிட்டீர்கள்."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"உங்கள் தரவு நீக்கப்படும்"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"அடுத்த முறை தவறான பேட்டர்னை வரைந்தால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"நீங்கள் பகிரும்போதோ ரெக்கார்டு செய்யும்போதோ அலைபரப்பும்போதோ உங்கள் திரையில் காட்டப்படுகின்ற அல்லது சாதனத்தில் பிளே செய்யப்படுகின்ற அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ஆப்ஸால் அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"நீங்கள் ஓர் ஆப்ஸைப் பகிரும்போதோ ரெக்கார்டு செய்யும்போதோ அலைபரப்பும்போதோ அந்த ஆப்ஸில் காட்டப்படுகின்ற அல்லது பிளே செய்யப்படுகின்ற அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ஆப்ஸால் அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"தொடங்கு"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இந்த விருப்பத்தை முடக்கியுள்ளது"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"அலைபரப்பைத் தொடங்கவா?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"நீங்கள் அலைபரப்பும்போது உங்கள் திரையில் காட்டப்படுகின்ற அல்லது சாதனத்தில் பிளே செய்யப்படுகின்ற அனைத்தையும் Android அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"ஓர் ஆப்ஸை நீங்கள் அலைபரப்பும்போது அந்த ஆப்ஸில் காட்டப்படுகின்ற அல்லது பிளே செய்யப்படுகின்ற அனைத்தையும் Android அணுக முடியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"அசிஸ்டண்ட்டின் கவனம் இயக்கத்தில் உள்ளது"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string>
     <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"மைக்ரோஃபோனும் கேமராவும்"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"சமீபத்திய ஆப்ஸ் பயன்பாடு"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"சமீபத்திய அணுகலைக் காட்டு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 421fec6..22a329b 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"మరొక పరికరం ద్వారా సిస్టమ్ భాష మార్పు రిక్వెస్ట్ చేయబడింది"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"భాషను మార్చండి"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ప్రస్తుత భాషను అలా ఉంచండి"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi షేర్ చేయండి"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"ఈ నెట్‌వర్క్ ద్వారా వైర్‌లెస్ డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"నెట్‌వర్క్ పేరు (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi అడ్రస్ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"ఈ నెట్‌వర్క్ నుండి ఎల్లప్పుడూ అనుమతించండి"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"ఆకృతి తప్పు"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"పాస్‌వర్డ్ తప్పు"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"చాలా ఎక్కువ తప్పు ప్రయత్నాలు చేశారు.\n<xliff:g id="NUMBER">%d</xliff:g> సెకన్ల తర్వాత మళ్లీ ట్రై చేయండి."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ఎమర్జెన్సీ"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"మళ్లీ ట్రై చేయండి. <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>లో <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> ప్రయత్నం చేశారు."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"మీ డేటా తొలగించబడుతుంది"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"మీరు ఒకవేళ తర్వాతి ప్రయత్నంలో తప్పు ఆకృతిని ఎంటర్ చేస్తే, ఈ పరికరం యొక్క డేటా తొలగించబడుతుంది."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"మీరు షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై కనిపించే దేనికైనా లేదా మీ పరికరంలో ప్లే అయిన దేనికైనా <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌కు యాక్సెస్ ఉంటుంది. కాబట్టి పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"మీరు ఏదైనా యాప్‌ను షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, ఆ యాప్‌లో చూపబడిన దేనికైనా లేదా ప్లే అయిన దేనికైనా <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌కు యాక్సెస్ ఉంటుంది. కాబట్టి పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"ప్రారంభించండి"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ఈ ఆప్షన్‌ను డిజేబుల్ చేసింది"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"ప్రసారాన్ని ప్రారంభించాలా?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"మీరు ప్రసారం చేసేటప్పుడు, మీ స్క్రీన్‌పై కనిపించే దేనికైనా లేదా మీ పరికరంలో ప్లే అయిన దేనికైనా Androidకు యాక్సెస్ ఉంటుంది. కాబట్టి పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"మీరు ఏదైనా యాప్‌ను ప్రసారం చేసేటప్పుడు, ఆ యాప్‌లో చూపబడిన దేనికైనా లేదా ప్లే అయిన దేనికైనా Androidకు యాక్సెస్ ఉంటుంది. కాబట్టి పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistant అటెన్షన్ ఆన్‌లో ఉంది"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్‌లలో ఆటోమేటిక్‌గా ఉండేలా ఒక నోట్స్ యాప్‌ను సెట్ చేసుకోండి"</string>
     <string name="install_app" msgid="5066668100199613936">"యాప్‌ను ఇన్‌స్టాల్ చేయండి"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"మైక్రోఫోన్ &amp; కెమెరా"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"ఇటీవలి యాప్ వినియోగం"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ఇటీవలి యాక్సెస్‌ను చూడండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0590806..3887b9f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"คำขอเปลี่ยนภาษาของระบบโดยอุปกรณ์อื่น"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"เปลี่ยนภาษา"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"ใช้ภาษาปัจจุบันต่อไป"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"แชร์ Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"อนุญาตให้แก้ไขข้อบกพร่องผ่าน Wi-Fi ในเครือข่ายนี้ใช่ไหม"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"ชื่อเครือข่าย (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nที่อยู่ Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"อนุญาตเสมอในเครือข่ายนี้"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"รูปแบบไม่ถูกต้อง"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"รหัสผ่านไม่ถูกต้อง"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"ดำเนินการไม่ถูกต้องหลายครั้งเกินไป\nลองอีกครั้งใน <xliff:g id="NUMBER">%d</xliff:g> วินาที"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ฉุกเฉิน"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"ลองอีกครั้ง ความพยายามครั้งที่ <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> จาก <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"ระบบจะลบข้อมูลของคุณ"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"หากคุณป้อนรูปแบบไม่ถูกต้องในความพยายามครั้งถัดไป ระบบจะลบข้อมูลในอุปกรณ์เครื่องนี้"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"เมื่อกำลังแชร์ บันทึก หรือแคสต์ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะมีสิทธิ์เข้าถึงทุกสิ่งที่ปรากฏบนหน้าจอหรือเล่นอยู่ในอุปกรณ์ ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"เมื่อกำลังแชร์ บันทึก หรือแคสต์แอป <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะมีสิทธิ์เข้าถึงทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"เริ่ม"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ปิดใช้ตัวเลือกนี้"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"เริ่มแคสต์เลยไหม"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"เมื่อกำลังแคสต์ Android จะมีสิทธิ์เข้าถึงทุกสิ่งที่ปรากฏบนหน้าจอหรือเล่นอยู่ในอุปกรณ์ ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"เมื่อกำลังแคสต์แอป Android จะมีสิทธิ์เข้าถึงทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"การเรียกใช้งาน Assistant เปิดอยู่"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string>
     <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"ไมโครโฟนและกล้อง"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"การใช้แอปครั้งล่าสุด"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"ดูการเข้าถึงล่าสุด"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 859191a..2fdee72 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Hiniling ng ibang device na palitan ang wika ng system"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Palitan ang wika"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Huwag palitan ang wika"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Ibahagi ang Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Payagan ang wireless na pag-debug sa network na ito?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Pangalan ng Network (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAddress ng Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Palaging payagan sa network na ito"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Maling pattern"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Maling password"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Masyadong maraming maling pagsubok.\nSubukan ulit sa loob ng <xliff:g id="NUMBER">%d</xliff:g> (na) segundo."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Emergency"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Subukan ulit. ika-<xliff:g id="ATTEMPTS_0">%1$d</xliff:g> (na) pagsubok sa <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Made-delete ang iyong data"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Kung maling pattern ang mailalagay mo sa susunod na pagsubok, made-delete ang data ng device na ito."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Kapag nagbabahagi, nagre-record, o nagka-cast ka, may access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa kahit anong nakikita sa iyong screen o pine-play sa device mo. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Kapag nagbabahagi, nagre-record, o nagka-cast ka ng app, may access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Simulan"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Na-disable ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang opsyong ito"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Simulan ang pag-cast?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Kapag nagka-cast ka, may access ang Android sa kahit anong nakikita sa iyong screen o pine-play sa device mo. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Kapag nagka-cast ka ng app, may access ang Android sa kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
@@ -1173,6 +1170,8 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Naka-on ang atensyon ng Assistant"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string>
     <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string>
+    <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string>
+    <string name="enable_display" msgid="8308309634883321977">"I-enable ang display"</string>
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikropono at Camera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Kamakailang paggamit ng app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Tingnan ang kamakailang access"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f217f13..b01fee1 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Başka bir cihaz tarafından sistem dilinin değiştirilmesi istendi"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Dili değiştir"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Mevcut dili koru"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Kablosuz ağı paylaşın"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Bu ağda kablosuz hata ayıklamaya izin verilsin mi?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Ağ Adı (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nKablosuz Adresi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu ağda her zaman izin ver"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Yanlış desen"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Yanlış şifre"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Çok fazla yanlış giriş yapıldı.\n<xliff:g id="NUMBER">%d</xliff:g> saniye içinde tekrar deneyin."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Acil durum"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Tekrar deneyin. Deneme sayısı: <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Verileriniz silinecek"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Bir sonraki denemenizde yanlış desen girerseniz bu cihazın verileri silinir."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Paylaşma, kaydetme ve yayınlama özelliklerini kullandığınızda <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görünen veya cihazınızda oynatılan her şeye erişebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Bir uygulamayı paylaştığınızda, kaydettiğinizde veya yayınladığınızda <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, söz konusu uygulamada gösterilen veya oynatılan her şeye erişebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Başlat"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> bu seçeneği devre dışı bıraktı"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Yayın başlatılsın mı?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Yayınlama özelliğini kullandığınızda Android, ekranınızda görünen veya cihazınızda oynatılan her şeye erişebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Bir uygulamayı yayınladığınızda Android, söz konusu uygulamada gösterilen veya oynatılan her şeye erişebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Asistan dinliyor"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string>
     <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon ve Kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Son uygulama kullanımı"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Son erişimi göster"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 83bfd63..db34413 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Запит на змінення мови системи надіслано з іншого пристрою"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Змінити мову"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Залишити поточну мову"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Поділитися Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Дозволити налагодження через Wi-Fi у цій мережі?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Ім\'я мережі (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nАдреса Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Завжди дозволяти в цій мережі"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Неправильний ключ"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Неправильний пароль"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Забагато невдалих спроб.\nПовторіть за <xliff:g id="NUMBER">%d</xliff:g> с."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Екстрений виклик"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Спробуйте ще. Спроба <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> із <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Ваші дані буде видалено"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Якщо наступного разу ви введете неправильний ключ, дані на цьому пристрої буде видалено."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Коли ви показуєте, записуєте або транслюєте екран, додаток <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримує доступ до всього, що відображається на екрані чи відтворюється на пристрої. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Коли ви показуєте, записуєте або транслюєте додаток, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримує доступ до всього, що відображається або відтворюється в цьому додатку. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Почати"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> вимкнув цю опцію"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Почати трансляцію?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Під час трансляції ОС Android отримує доступ до всього, що відображається на екрані чи відтворюється на пристрої. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Коли ви транслюєте додаток, ОС Android отримує доступ до всього, що відображається або відтворюється в ньому. Тому будьте уважні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Асистента активовано"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string>
     <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Мікрофон і камера"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Нещодавнє використання додатками"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Переглянути нещодавній доступ"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index eac34ce..8115e2e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"کسی دوسرے آلے کے ذریعے سسٹم کی زبان میں تبدیلی کی درخواست کی گئی"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"زبان تبدیل کریں"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"موجودہ زبان برقرار رکھیں"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"‏Wi-Fi کا اشتراک کریں"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"اس نیٹ ورک پر وائرلیس ڈیبگنگ کرنے کی اجازت دیں؟"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"‏نیٹ ورک کا نام (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\n‏ Wi-Fi کا پتہ (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"اس نیٹ ورک پر ہمیشہ اجازت دیں"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"غلط پیٹرن"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"غلط پاس ورڈ"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"کافی زیادہ غلط کوششیں کی گئیں۔\n <xliff:g id="NUMBER">%d</xliff:g> سیکنڈ بعد دوبارہ کوشش کریں۔"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"ایمرجنسی"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"دوبارہ کوشش کریں۔ کوشش <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> از <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>۔"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"آپ کا ڈیٹا حذف کر دیا جائے گا"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"اگر آپ نے اگلی کوشش میں غلط پیٹرن درج کیا تو اس آلے کا ڈیٹا حذف کر دیا جائے گا۔"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"جب آپ اشتراک، ریکارڈنگ یا کاسٹ کر رہے ہوتے ہیں تو <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کو آپ کی اسکرین پر دکھائی دینے والی یا آپ کے آلے پر چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"جب آپ اشتراک، ریکارڈنگ یا کسی ایپ کو کاسٹ کر رہے ہوتے ہیں تو <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کو اس ایپ پر دکھائی گئی یا چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"شروع کریں"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> نے اس اختیار کو غیر فعال کر دیا ہے"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"کاسٹ کرنا شروع کریں؟"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"‏جب آپ کاسٹ کر رہے ہوتے ہیں، تو Android کو آپ کی اسکرین پر دکھائی دینے والی یا آپ کے آلے پر چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"‏جب آپ کسی ایپ کو کاسٹ کر رہے ہوتے ہیں تو Android کو اس ایپ پر دکھائی گئی یا چلائی گئی ہر چیز تک رسائی حاصل ہوتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"اسسٹنٹ کی توجہ آن ہے"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string>
     <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"مائیکروفون اور کیمرا"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"حالیہ ایپ کا استعمال"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"حالیہ رسائی دیکھیں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 66c874d..30e0618 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Tizim tilini oʻzgartirishni boshqa qurilma soʻragan"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Tilni almashtirish"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Joriy tilni qoldirish"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi ulashuv"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Tarmoq nomi (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Manzil (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu tarmoqda doim ruxsat etilsin"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Grafik kalit xato"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Parol xato"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Xato urinishlar soni oshib ketdi! \n <xliff:g id="NUMBER">%d</xliff:g> soniyadan keyin qayta urining."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Favqulodda holat"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Qaytadan urining. Urinish: <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> / <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Bitta urinish qoldi"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Agar grafik kalitni xato kiritsangiz, bu qurilmadagi maʼlumotlar oʻchirib tashlanadi."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Ulashish, yozib olish va translatsiya qilish vaqtida <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Ulashish, yozib olish va translatsiya qilish vaqtida <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Boshlash"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> bu sozlamani faolsizlantirgan"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Translatsiya boshlansinmi?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Translatsiya qilayotganingizda Android ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Translatsiya qilayotganingizda Android ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Assistent diqqati yoniq"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string>
     <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Mikrofon va kamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ilovadan oxirgi foydalanish"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Oxirgi ruxsatni koʻrish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 2648d78..f4c62a5 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Thiết bị khác yêu cầu thay đổi ngôn ngữ hệ thống"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Thay đổi ngôn ngữ"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Giữ ngôn ngữ hiện tại"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Chia sẻ Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Cho phép gỡ lỗi qua Wi-Fi trên mạng này?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Tên mạng (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nĐịa chỉ Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Luôn cho phép trên mạng này"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Hình mở khóa không chính xác"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Mật khẩu sai"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Bạn đã nhập sai quá nhiều lần.\nHãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Khẩn cấp"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Thử lại. Lần thử <xliff:g id="ATTEMPTS_0">%1$d</xliff:g>/<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Dữ liệu của bạn sẽ bị xóa"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Nếu bạn nhập hình mở khóa không chính xác vào lần thử tiếp theo, thì dữ liệu trên thiết bị này sẽ bị xóa."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Khi bạn chia sẻ, ghi hoặc truyền, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào mọi nội dung xuất hiện trên màn hình hoặc phát trên thiết bị của bạn. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Khi bạn chia sẻ, ghi hoặc truyền ứng dụng, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào mọi nội dung xuất hiện hoặc phát trên ứng dụng đó. Vì vậy, hãy thận trọng để không làm lộ các thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Bắt đầu"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> đã tắt lựa chọn này"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Bắt đầu truyền?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Khi bạn truyền, Android sẽ có quyền truy cập vào mọi nội dung xuất hiện trên màn hình hoặc phát trên thiết bị của bạn. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Khi bạn truyền một ứng dụng, Android sẽ có quyền truy cập vào mọi nội dung xuất hiện hoặc phát trên ứng dụng đó. Vì vậy, hãy thận trọng để không làm lộ các thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Trợ lý đang bật"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string>
     <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Micrô và máy ảnh"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Hoạt động sử dụng gần đây của ứng dụng"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Xem hoạt động truy cập gần đây"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3072fa4..f3ade03 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"另一台设备请求更改系统语言"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"更改语言"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"保持当前语言"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"分享 WLAN"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"要允许通过此网络进行无线调试吗?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"网络名称 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWLAN 地址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"始终允许通过此网络进行调试"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"图案错误"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"密码错误"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"输错次数过多。\n请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"紧急呼叫"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"请重试。您目前已尝试 <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> 次,最多可尝试 <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> 次。"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"您的数据将会被删除"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"如果您下次绘制的解锁图案仍然有误,此设备上的数据将会被删除。"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"在分享、录制或投放内容时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>可以访问屏幕上显示或设备中播放的所有内容。因此,请务必小心操作,谨防密码、付款信息、消息、照片、音频和视频等内容遭到泄露。"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"在分享、录制或投放内容时,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>可以访问通过此应用显示或播放的所有内容。因此,请务必小心操作,谨防密码、付款信息、消息、照片、音频和视频等内容遭到泄露。"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"开始"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已停用此选项"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"开始投放?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"在投放内容时,Android 可以访问屏幕上显示或设备中播放的所有内容。因此,请务必小心操作,谨防密码、付款信息、消息、照片、音频和视频等内容遭到泄露。"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"在投放某个应用时,Android 可以访问此应用显示或播放的所有内容。因此,请务必小心操作,谨防密码、付款信息、消息、照片、音频和视频等内容遭到泄露。"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"已开启 Google 助理感知功能"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string>
     <string name="install_app" msgid="5066668100199613936">"安装应用"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"麦克风和摄像头"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期应用对手机传感器的使用情况"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期使用情况"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 8f4adc0..efc5671 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"另一部裝置要求變更系統語言"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"變更語言"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"保留目前語言"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"分享 Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"要在此網絡上允許無線偵錯功能嗎?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"網絡名稱 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi 地址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"一律允許在此網絡上執行"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"圖案錯誤"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"密碼錯誤"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"輸入錯誤的次數太多,\n請於 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試。"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"緊急"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"請再試一次。你已嘗試 <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> 次,最多可試 <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> 次。"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"你的資料將會刪除"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"如果你下次畫出錯誤的上鎖圖案,系統將會刪除此裝置上的資料。"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"當你分享、錄影或投放時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"當你分享、錄影或投放應用程式時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取顯示在該應用程式中顯示或播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"開始"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」已停用此選項"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"要開始投放嗎?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"當你投放時,Android 可存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"當你投放應用程式時,Android 可存取在該應用程式中顯示或播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"「Google 助理」感應功能已開啟"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string>
     <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"近期應用程式使用情況"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 35b7231b..af84a31 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"另一部裝置要求變更系統語言"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"變更語言"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"繼續使用目前的語言"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"分享 Wi-Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"要允許透過這個網路執行無線偵錯嗎?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"網路名稱 (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi 位址 (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"一律允許透過這個網路執行"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"圖案錯誤"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"密碼錯誤"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"錯誤次數過多,\n請於 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試。"</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"緊急"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"請再試一次。你目前已嘗試 <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> 次,最多可試 <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g> 次。"</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"你的資料將遭到刪除"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"如果下次輸入的解鎖圖案仍不正確,系統將刪除這部裝置中的資料。"</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"當你分享、錄製或投放內容時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取畫面上顯示的任何資訊或裝置播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"當你分享、錄製或投放應用程式內容時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取應用程式中顯示的任何資訊或播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"開始"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」已停用此選項"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"要開始投放嗎?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"當你投放內容時,Android 可存取畫面上顯示的任何資訊或裝置播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"當你投放應用程式內容時,Android 可存取應用程式中顯示的任何資訊或播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Google 助理感知功能已開啟"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string>
     <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"麥克風和相機"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"最近曾使用感應器的應用程式"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"查看近期存取記錄"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 19c00e6..11cf44b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -57,8 +57,7 @@
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Ushintsho lolimi lwesistimu lucelwe enye idivayisi"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Shintsha ulimi"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Gcina ulimi lwamanje"</string>
-    <!-- no translation found for share_wifi_button_text (1285273973812029240) -->
-    <skip />
+    <string name="share_wifi_button_text" msgid="1285273973812029240">"Yaba i-Wi‑Fi"</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"Vumela ukulungisa amaphutha okungenantambo kule nethiwekhi?"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"Igama Lenethiwekhi (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nIkheli le-Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Njalo nje vumela le nethiwekhi"</string>
@@ -160,8 +159,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="8954812279840889029">"Iphethini engalungile"</string>
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Iphasiwedi engalungile"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Imizamo eminingi kakhulu engalungile.\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER">%d</xliff:g>."</string>
-    <!-- no translation found for work_challenge_emergency_button_text (8946588434515599288) -->
-    <skip />
+    <string name="work_challenge_emergency_button_text" msgid="8946588434515599288">"Isimo esiphuthumayo"</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Zama futhi. Umzamo ongu-<xliff:g id="ATTEMPTS_0">%1$d</xliff:g> kwengu-<xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
     <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Idatha yakho izosuswa"</string>
     <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Uma ufaka iphethini engalungile kumzamo olandelayo, idatha yale divayisi izosuswa."</string>
@@ -415,8 +413,7 @@
     <string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Uma wabelana, urekhoda, noma usakaza, i-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inokufinyelela kunoma yini ebonakalayo kusikrini sakho noma edlalwa kudivayisi yakho. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yokukhokha, imilayezo, izithombe, nomsindo nevidiyo."</string>
     <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Uma wabelana, ukurekhoda, noma ukusakaza ku-app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inokufinyelela kunoma yini eboniswayo noma edlalwa kuleyo app. Ngakho-ke qaphela ngezinto ezfana namaphasiwedi, imininingwane yokukhokha, imilayezo, izithombe, nomsindo nevidiyo."</string>
     <string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Qala"</string>
-    <!-- no translation found for media_projection_entry_app_permission_dialog_single_app_disabled (8999903044874669995) -->
-    <skip />
+    <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ivale le nketho"</string>
     <string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Qala ukusakaza?"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Uma usakaza, i-Android inokufinyelela kunoma yini ebonakalayo kusikrini sakho noma edlalwa kudivayisi yakho. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yokukhokha, imilayezo, izithombe, nomsindo nevidiyo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Uma usakaza i-app, i-Android inokufinyelela kunoma yini eboniswayo noma edlalwa kuleyo app. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yenkokhelo, imilayezo, izithombe, nomsindo nevidiyo."</string>
@@ -1173,6 +1170,10 @@
     <string name="assistant_attention_content_description" msgid="6830215897604642875">"Ukunaka kwe-Assistant kuvuliwe"</string>
     <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string>
     <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string>
+    <!-- no translation found for connected_display_dialog_start_mirroring (6237895789920854982) -->
+    <skip />
+    <!-- no translation found for enable_display (8308309634883321977) -->
+    <skip />
     <string name="privacy_dialog_title" msgid="7839968133469098311">"Imakrofoni Nekhamera"</string>
     <string name="privacy_dialog_summary" msgid="2458769652125995409">"Ukusetshenziswa kwakamuva kwe-app"</string>
     <string name="privacy_dialog_more_button" msgid="7610604080293562345">"Bona ukufinyelela kwakamuva"</string>
diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml
index 405a59f..91d3a88 100644
--- a/packages/SystemUI/res/values/bools.xml
+++ b/packages/SystemUI/res/values/bools.xml
@@ -51,4 +51,12 @@
          This configuration will only apply when config_remoteInsetsControllerControlsSystemBars.
          is set to true. -->
     <bool name="config_remoteInsetsControllerSystemBarsCanBeShownByUserAction">false</bool>
+
+    <!--  Do update bouncer constraints (port or land) on rotation.
+      Needed for bouncer refactor to use motion layout, because constraints should only be
+      changed on small screens. Only used when flag "lockscreen.enable_landscape" (b/293252410)
+      is enabled
+
+      True here so bouncers constraints are updated when rotating on small screens -->
+    <bool name="update_bouncer_constraints">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 016936a..c134806 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -934,4 +934,12 @@
 
     <!-- Flag controlling whether visual query attention detection has been enabled. -->
     <bool name="config_enableVisualQueryAttentionDetection">false</bool>
+
+    <!--
+    Whether the scene container framework is enabled.
+
+    The scene container framework is a newer (2023) way to organize the various "scenes" between the
+    bouncer, lockscreen, shade, and quick settings.
+    -->
+    <bool name="config_sceneContainerFrameworkEnabled">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 579358f..d8c8080 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -233,4 +233,7 @@
     removed later.
     -->
     <item type="id" name="tag_smartspace_view" />
+
+    <!-- Tag set on the Compose implementation of the QS footer actions. -->
+    <item type="id" name="tag_compose_qs_footer_actions" />
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b37aeee..6840108 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3184,6 +3184,12 @@
     <!-- Label for a button that, when clicked, sends the user to the app store to install an app. [CHAR LIMIT=64]. -->
     <string name="install_app">Install app</string>
 
+    <!--- Title of the dialog appearing when an external display is connected, asking whether to start mirroring [CHAR LIMIT=NONE]-->
+    <string name="connected_display_dialog_start_mirroring">Mirror to external display?</string>
+
+    <!--- Label of the "enable display" button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]-->
+    <string name="enable_display">Enable display</string>
+
     <!-- Title of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=30] -->
     <string name="privacy_dialog_title">Microphone &amp; Camera</string>
     <!-- Subtitle of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 0cdc0f9..8bf7560d 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -54,10 +54,12 @@
         android:layout_marginStart="@dimen/qs_media_padding"
         android:layout_marginEnd="@dimen/qs_media_padding"
         app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+        app:layout_constraintTop_toBottomOf="@id/media_seamless"
         app:layout_constrainedWidth="true"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintBottom_toTopOf="@id/header_artist"
-        app:layout_constraintHorizontal_bias="0" />
+        app:layout_constraintHorizontal_bias="0"
+        app:layout_constraintVertical_bias="1" />
 
     <Constraint
         android:id="@+id/media_explicit_indicator"
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index ca30e15..a6517c1 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -50,6 +50,7 @@
         "SystemUIAnimationLib",
         "SystemUIPluginLib",
         "SystemUIUnfoldLib",
+        "SystemUISharedLib-Keyguard",
         "androidx.dynamicanimation_dynamicanimation",
         "androidx.concurrent_concurrent-futures",
         "androidx.lifecycle_lifecycle-runtime-ktx",
diff --git a/packages/SystemUI/shared/keyguard/Android.bp b/packages/SystemUI/shared/keyguard/Android.bp
new file mode 100644
index 0000000..2181439
--- /dev/null
+++ b/packages/SystemUI/shared/keyguard/Android.bp
@@ -0,0 +1,16 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+android_library {
+    name: "SystemUISharedLib-Keyguard",
+    srcs: [
+        "src/**/*.java",
+    ],
+    min_sdk_version: "current",
+}
diff --git a/packages/SystemUI/shared/keyguard/AndroidManifest.xml b/packages/SystemUI/shared/keyguard/AndroidManifest.xml
new file mode 100644
index 0000000..49bee08
--- /dev/null
+++ b/packages/SystemUI/shared/keyguard/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.systemui.shared.keyguard">
+</manifest>
\ No newline at end of file
diff --git a/packages/SystemUI/shared/keyguard/src/com/android/keyguard/BasePasswordTextView.java b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/BasePasswordTextView.java
new file mode 100644
index 0000000..fe12134
--- /dev/null
+++ b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/BasePasswordTextView.java
@@ -0,0 +1,239 @@
+/*
+ * 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.keyguard;
+
+import android.annotation.CallSuper;
+import android.content.Context;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+
+/**
+ * A View similar to a textView which contains password text and can animate when the text is
+ * changed
+ */
+public abstract class BasePasswordTextView extends FrameLayout {
+    private String mText = "";
+    private UserActivityListener mUserActivityListener;
+    protected boolean mIsPinHinting;
+    protected PinShapeInput mPinShapeInput;
+    protected boolean mShowPassword = true;
+    protected boolean mUsePinShapes = false;
+    protected static final char DOT = '\u2022';
+
+    /** Listens to user activities like appending, deleting and resetting PIN text */
+    public interface UserActivityListener {
+
+        /** Listens to user activities. */
+        void onUserActivity();
+    }
+
+    public BasePasswordTextView(Context context) {
+        this(context, null);
+    }
+
+    public BasePasswordTextView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BasePasswordTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public BasePasswordTextView(
+            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    protected abstract PinShapeInput inflatePinShapeInput(boolean isPinHinting);
+
+    protected abstract boolean shouldSendAccessibilityEvent();
+
+    protected void onAppend(char c, int newLength) {}
+
+    protected void onDelete(int index) {}
+
+    protected void onReset(boolean animated) {}
+
+    @CallSuper
+    protected void onUserActivity() {
+        if (mUserActivityListener != null) {
+            mUserActivityListener.onUserActivity();
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    /** Appends a PIN text */
+    public void append(char c) {
+        CharSequence textbefore = getTransformedText();
+
+        mText = mText + c;
+        int newLength = mText.length();
+        onAppend(c, newLength);
+
+        if (mPinShapeInput != null) {
+            mPinShapeInput.append();
+        }
+
+        onUserActivity();
+
+        sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length(), 0, 1);
+    }
+
+    /** Sets a listener who is notified on user activity */
+    public void setUserActivityListener(UserActivityListener userActivityListener) {
+        mUserActivityListener = userActivityListener;
+    }
+
+    /** Deletes the last PIN text */
+    public void deleteLastChar() {
+        int length = mText.length();
+        if (length > 0) {
+            CharSequence textbefore = getTransformedText();
+
+            mText = mText.substring(0, length - 1);
+            onDelete(length - 1);
+
+            if (mPinShapeInput != null) {
+                mPinShapeInput.delete();
+            }
+
+            sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
+        }
+        onUserActivity();
+    }
+
+    /** Gets entered PIN text */
+    public String getText() {
+        return mText;
+    }
+
+    /** Gets a transformed text for accessibility event. Called before text changed. */
+    protected CharSequence getTransformedText() {
+        return String.valueOf(DOT).repeat(mText.length());
+    }
+
+    /** Gets a transformed text for accessibility event. Called after text changed. */
+    protected CharSequence getTransformedText(int fromIndex, int removedCount, int addedCount) {
+        return getTransformedText();
+    }
+
+    /** Reset PIN text without error */
+    public void reset(boolean animated, boolean announce) {
+        reset(false /* error */, animated, announce);
+    }
+
+    /** Reset PIN text */
+    public void reset(boolean error, boolean animated, boolean announce) {
+        CharSequence textbefore = getTransformedText();
+
+        mText = "";
+
+        onReset(animated);
+        if (animated) {
+            onUserActivity();
+        }
+
+        if (mPinShapeInput != null) {
+            if (error) {
+                mPinShapeInput.resetWithError();
+            } else {
+                mPinShapeInput.reset();
+            }
+        }
+
+        if (announce) {
+            sendAccessibilityEventTypeViewTextChanged(textbefore, 0, textbefore.length(), 0);
+        }
+    }
+
+    void sendAccessibilityEventTypeViewTextChanged(
+            CharSequence beforeText, int fromIndex, int removedCount, int addedCount) {
+        if (AccessibilityManager.getInstance(mContext).isEnabled()
+                && shouldSendAccessibilityEvent()) {
+            AccessibilityEvent event =
+                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
+            event.setFromIndex(fromIndex);
+            event.setRemovedCount(removedCount);
+            event.setAddedCount(addedCount);
+            event.setBeforeText(beforeText);
+            CharSequence transformedText = getTransformedText(fromIndex, removedCount, addedCount);
+            if (!TextUtils.isEmpty(transformedText)) {
+                event.getText().add(transformedText);
+            }
+            event.setPassword(true);
+            sendAccessibilityEventUnchecked(event);
+        }
+    }
+
+    /** Sets whether to use pin shapes. */
+    public void setUsePinShapes(boolean usePinShapes) {
+        mUsePinShapes = usePinShapes;
+    }
+
+    /** Determines whether AutoConfirmation feature is on. */
+    public void setIsPinHinting(boolean isPinHinting) {
+        // Do not reinflate the view if we are using the same one.
+        if (mPinShapeInput != null && mIsPinHinting == isPinHinting) {
+            return;
+        }
+        mIsPinHinting = isPinHinting;
+
+        if (mPinShapeInput != null) {
+            removeView(mPinShapeInput.getView());
+            mPinShapeInput = null;
+        }
+
+        mPinShapeInput = inflatePinShapeInput(isPinHinting);
+        addView(mPinShapeInput.getView());
+    }
+
+    /** Controls whether the last entered digit is briefly shown after being entered */
+    public void setShowPassword(boolean enabled) {
+        mShowPassword = enabled;
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+
+        event.setClassName(EditText.class.getName());
+        event.setPassword(true);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+
+        info.setClassName(EditText.class.getName());
+        info.setPassword(true);
+        info.setText(getTransformedText());
+
+        info.setEditable(true);
+
+        info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeInput.java b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/PinShapeInput.java
similarity index 85%
rename from packages/SystemUI/src/com/android/keyguard/PinShapeInput.java
rename to packages/SystemUI/shared/keyguard/src/com/android/keyguard/PinShapeInput.java
index 52ae6ba..d2b4066 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeInput.java
+++ b/packages/SystemUI/shared/keyguard/src/com/android/keyguard/PinShapeInput.java
@@ -44,6 +44,14 @@
     void reset();
 
     /**
+     * This is the method that is triggered for resetting the view with error If it doesn't have to
+     * show something regarding error, just reset
+     */
+    default void resetWithError() {
+        reset();
+    }
+
+    /**
      * This is the method that is triggered for getting the view
      */
     View getView();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index 6b67c09..7719e95 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -55,7 +55,9 @@
     private final PluginListener<T> mListener;
     private final ComponentName mComponentName;
     private final PluginFactory<T> mPluginFactory;
+    private final String mTag;
 
+    private boolean mIsDebug = false;
     private Context mPluginContext;
     private T mPlugin;
 
@@ -71,27 +73,51 @@
         mComponentName = componentName;
         mPluginFactory = pluginFactory;
         mPlugin = plugin;
+        mTag = TAG + mComponentName.toShortString()
+                + '@' + Integer.toHexString(hashCode());
 
         if (mPlugin != null) {
             mPluginContext = mPluginFactory.createPluginContext();
         }
     }
 
+    @Override
+    public String toString() {
+        return mTag;
+    }
+
+    public boolean getIsDebug() {
+        return mIsDebug;
+    }
+
+    public void setIsDebug(boolean debug) {
+        mIsDebug = debug;
+    }
+
+    private void logDebug(String message) {
+        if (mIsDebug) {
+            Log.i(mTag, message);
+        }
+    }
+
     /** Alerts listener and plugin that the plugin has been created. */
     public void onCreate() {
         boolean loadPlugin = mListener.onPluginAttached(this);
         if (!loadPlugin) {
             if (mPlugin != null) {
+                logDebug("onCreate: auto-unload");
                 unloadPlugin();
             }
             return;
         }
 
         if (mPlugin == null) {
+            logDebug("onCreate auto-load");
             loadPlugin();
             return;
         }
 
+        logDebug("onCreate: load callbacks");
         mPluginFactory.checkVersion(mPlugin);
         if (!(mPlugin instanceof PluginFragment)) {
             // Only call onCreate for plugins that aren't fragments, as fragments
@@ -103,6 +129,7 @@
 
     /** Alerts listener and plugin that the plugin is being shutdown. */
     public void onDestroy() {
+        logDebug("onDestroy");
         unloadPlugin();
         mListener.onPluginDetached(this);
     }
@@ -118,15 +145,18 @@
      */
     public void loadPlugin() {
         if (mPlugin != null) {
+            logDebug("Load request when already loaded");
             return;
         }
 
         mPlugin = mPluginFactory.createPlugin();
         mPluginContext = mPluginFactory.createPluginContext();
         if (mPlugin == null || mPluginContext == null) {
+            Log.e(mTag, "Requested load, but failed");
             return;
         }
 
+        logDebug("Loaded plugin; running callbacks");
         mPluginFactory.checkVersion(mPlugin);
         if (!(mPlugin instanceof PluginFragment)) {
             // Only call onCreate for plugins that aren't fragments, as fragments
@@ -143,9 +173,11 @@
      */
     public void unloadPlugin() {
         if (mPlugin == null) {
+            logDebug("Unload request when already unloaded");
             return;
         }
 
+        logDebug("Unloading plugin, running callbacks");
         mListener.onPluginUnloaded(mPlugin, this);
         if (!(mPlugin instanceof PluginFragment)) {
             // Only call onDestroy for plugins that aren't fragments, as fragments
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 06b6692..1703b30 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -48,6 +48,7 @@
     private static final long STATUS_AREA_MOVE_UP_MILLIS = 967;
     private static final long STATUS_AREA_MOVE_DOWN_MILLIS = 467;
     private static final float SMARTSPACE_TRANSLATION_CENTER_MULTIPLIER = 1.4f;
+    private static final float SMARTSPACE_TOP_PADDING_MULTIPLIER = 2.625f;
 
     @IntDef({LARGE, SMALL})
     @Retention(RetentionPolicy.SOURCE)
@@ -96,6 +97,14 @@
     private KeyguardClockFrame mLargeClockFrame;
     private ClockController mClock;
 
+    // It's bc_smartspace_view, assigned by KeyguardClockSwitchController
+    // to get the top padding for translating smartspace for weather clock
+    private View mSmartspace;
+
+    // Smartspace in weather clock is translated by this value
+    // to compensate for the position invisible dateWeatherView
+    private int mSmartspaceTop = -1;
+
     private KeyguardStatusAreaView mStatusArea;
     private int mSmartspaceTopOffset;
     private float mWeatherClockSmartspaceScaling = 1f;
@@ -134,8 +143,11 @@
     public void onConfigChanged() {
         mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
                 R.dimen.keyguard_clock_switch_y_shift);
-        mSmartspaceTopOffset = mContext.getResources().getDimensionPixelSize(
-                R.dimen.keyguard_smartspace_top_offset);
+        mSmartspaceTopOffset = (int) (mContext.getResources().getDimensionPixelSize(
+                        R.dimen.keyguard_smartspace_top_offset)
+                * mContext.getResources().getConfiguration().fontScale
+                / mContext.getResources().getDisplayMetrics().density
+                * SMARTSPACE_TOP_PADDING_MULTIPLIER);
         mWeatherClockSmartspaceScaling = ResourcesCompat.getFloat(
                 mContext.getResources(), R.dimen.weather_clock_smartspace_scale);
         mWeatherClockSmartspaceTranslateX = mContext.getResources().getDimensionPixelSize(
@@ -145,6 +157,12 @@
         updateStatusArea(/* animate= */false);
     }
 
+    /** Get bc_smartspace_view from KeyguardClockSwitchController
+     * Use its top to decide the translation value */
+    public void setSmartspace(View smartspace) {
+        mSmartspace = smartspace;
+    }
+
     /** Sets whether the large clock is being shown on a connected display. */
     public void setLargeClockOnSecondaryDisplay(boolean onSecondaryDisplay) {
         if (mClock != null) {
@@ -295,7 +313,7 @@
                     && mClock.getLargeClock().getConfig().getHasCustomWeatherDataDisplay()) {
                 statusAreaClockScale = mWeatherClockSmartspaceScaling;
                 statusAreaClockTranslateX = mWeatherClockSmartspaceTranslateX;
-                statusAreaClockTranslateY = mWeatherClockSmartspaceTranslateY;
+                statusAreaClockTranslateY = mWeatherClockSmartspaceTranslateY - mSmartspaceTop;
                 if (mSplitShadeCentered) {
                     statusAreaClockTranslateX *= SMARTSPACE_TRANSLATION_CENTER_MULTIPLIER;
                 }
@@ -418,10 +436,14 @@
             post(() -> updateClockTargetRegions());
         }
 
-        if (mDisplayedClockSize != null && !mChildrenAreLaidOut) {
+        if (mSmartspace != null && mSmartspaceTop != mSmartspace.getTop()) {
+            mSmartspaceTop = mSmartspace.getTop();
             post(() -> updateClockViews(mDisplayedClockSize == LARGE, mAnimateOnLayout));
         }
 
+        if (mDisplayedClockSize != null && !mChildrenAreLaidOut) {
+            post(() -> updateClockViews(mDisplayedClockSize == LARGE, mAnimateOnLayout));
+        }
         mChildrenAreLaidOut = true;
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 6d2880e..d897960 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -372,6 +372,7 @@
         mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
 
         mKeyguardUnlockAnimationController.setLockscreenSmartspace(mSmartspaceView);
+        mView.setSmartspace(mSmartspaceView);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
index c9d9069..a72d813 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -64,6 +64,11 @@
         return false;
     }
 
+    /** Change motion layout constraint set based on orientation */
+    protected void updateConstraints(int orientation) {
+        //Unless overridden, never update constrains (keeping default portrait constraints)
+    }
+
     protected AnimatorListenerAdapter getAnimationListener(int cuj) {
         return new AnimatorListenerAdapter() {
             private boolean mIsCancel;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index d90785d..a2d8c50 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -83,6 +83,7 @@
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -123,6 +124,7 @@
     private final UserSwitcherController mUserSwitcherController;
     private final GlobalSettings mGlobalSettings;
     private final FeatureFlags mFeatureFlags;
+    private final SceneContainerFlags mSceneContainerFlags;
     private final SessionTracker mSessionTracker;
     private final Optional<SideFpsController> mSideFpsController;
     private final FalsingA11yDelegate mFalsingA11yDelegate;
@@ -369,11 +371,9 @@
 
                 @Override
                 public void onOrientationChanged(int orientation) {
-                    if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) {
-                        // TODO(b/295603468)
-                        // Fix reinflation of views when flag is enabled.
-                        KeyguardSecurityContainerController.this
-                            .onDensityOrFontScaleOrOrientationChanged();
+                    if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
+                            && getResources().getBoolean(R.bool.update_bouncer_constraints)) {
+                        mSecurityViewFlipperController.updateConstraints(orientation);
                     }
                 }
             };
@@ -433,6 +433,7 @@
             FalsingManager falsingManager,
             UserSwitcherController userSwitcherController,
             FeatureFlags featureFlags,
+            SceneContainerFlags sceneContainerFlags,
             GlobalSettings globalSettings,
             SessionTracker sessionTracker,
             Optional<SideFpsController> sideFpsController,
@@ -466,6 +467,7 @@
         mFalsingManager = falsingManager;
         mUserSwitcherController = userSwitcherController;
         mFeatureFlags = featureFlags;
+        mSceneContainerFlags = sceneContainerFlags;
         mGlobalSettings = globalSettings;
         mSessionTracker = sessionTracker;
         mSideFpsController = sideFpsController;
@@ -503,7 +505,7 @@
 
         showPrimarySecurityScreen(false);
 
-        if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (mSceneContainerFlags.isEnabled()) {
             // When the scene framework says that the lockscreen has been dismissed, dismiss the
             // keyguard here, revealing the underlying app or launcher:
             mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 4d2391a..891eb14 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -83,6 +83,14 @@
         return "";
     }
 
+    /** Updates the keyguard view's constraints based on orientation */
+    public void updateConstraints(int orientation) {
+        KeyguardInputView securityView = getSecurityView();
+        if (securityView != null) {
+            securityView.updateConstraints(orientation);
+        }
+    }
+
     @Override
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return p instanceof LayoutParams;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index bc5b1ba..74f0beb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -16,6 +16,8 @@
 
 package com.android.keyguard;
 
+import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
+
 import android.util.Log;
 import android.view.LayoutInflater;
 
@@ -116,30 +118,38 @@
     public void asynchronouslyInflateView(SecurityMode securityMode,
             KeyguardSecurityCallback keyguardSecurityCallback,
             @Nullable OnViewInflatedCallback onViewInflatedListener) {
-        int layoutId = getLayoutIdFor(securityMode);
-        int viewID = getKeyguardInputViewId(securityMode);
-        if (layoutId != 0 && viewID != 0) {
+        int layoutId = mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
+                ? getLayoutIdFor(securityMode) : getLegacyLayoutIdFor(securityMode);
+        if (layoutId != 0) {
             if (DEBUG) {
-                Log.v(TAG, "inflating on bg thread id = "
-                        + layoutId + " . viewID = " + viewID);
+                Log.v(TAG, "inflating on bg thread id = " + layoutId + " .");
             }
             mAsyncLayoutInflater.inflate(layoutId, mView,
                     (view, resId, parent) -> {
                         mView.addView(view);
                         KeyguardInputViewController<KeyguardInputView> childController =
                                 mKeyguardSecurityViewControllerFactory.create(
-                                        (KeyguardInputView) view.findViewById(viewID),
+                                        (KeyguardInputView) view,
                                         securityMode, keyguardSecurityCallback);
                         childController.init();
                         mChildren.add(childController);
                         if (onViewInflatedListener != null) {
                             onViewInflatedListener.onViewInflated(childController);
+
+                            // Portrait constrains are default
+                            if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)
+                                    &&
+                                    getResources().getBoolean(R.bool.update_bouncer_constraints)) {
+                                // updateConstraints based on orientation (only on small screens)
+                                updateConstraints(getResources().getConfiguration().orientation);
+                            }
                         }
                     });
         }
     }
 
     private int getLayoutIdFor(SecurityMode securityMode) {
+        // TODO (b/297863911, b/297864907) - implement motion layout for other bouncers
         switch (securityMode) {
             case Pattern: return R.layout.keyguard_pattern_view;
             case PIN: return R.layout.keyguard_pin_view;
@@ -151,19 +161,23 @@
         }
     }
 
-    private int getKeyguardInputViewId(SecurityMode securityMode) {
-        //Keyguard Input View is not the root view of the layout, use these IDs for lookup.
+    private int getLegacyLayoutIdFor(SecurityMode securityMode) {
         switch (securityMode) {
-            case Pattern: return R.id.keyguard_pattern_view;
-            case PIN: return R.id.keyguard_pin_view;
-            case Password: return R.id.keyguard_password_view;
-            case SimPin: return R.id.keyguard_sim_pin_view;
-            case SimPuk: return R.id.keyguard_sim_puk_view;
+            case Pattern: return R.layout.keyguard_pattern_view;
+            case PIN: return R.layout.keyguard_pin_view;
+            case Password: return R.layout.keyguard_password_view;
+            case SimPin: return R.layout.keyguard_sim_pin_view;
+            case SimPuk: return R.layout.keyguard_sim_puk_view;
             default:
                 return 0;
         }
     }
 
+    /** Updates the keyguard view's constraints based on orientation */
+    public void updateConstraints(int orientation) {
+        mView.updateConstraints(orientation);
+    }
+
     /** Makes the supplied child visible if it is contained win this view, */
     public void show(KeyguardInputViewController<KeyguardInputView> childController) {
         int index = childController.getIndexIn(mView);
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 8611dbbb..1d37809 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -142,11 +142,13 @@
                 mLockIconCenter.y + mRadius);
 
         final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-        lp.width = (int) (mSensorRect.right - mSensorRect.left);
-        lp.height = (int) (mSensorRect.bottom - mSensorRect.top);
-        lp.topMargin = (int) mSensorRect.top;
-        lp.setMarginStart((int) mSensorRect.left);
-        setLayoutParams(lp);
+        if (lp != null) {
+            lp.width = (int) (mSensorRect.right - mSensorRect.left);
+            lp.height = (int) (mSensorRect.bottom - mSensorRect.top);
+            lp.topMargin = (int) mSensorRect.top;
+            lp.setMarginStart((int) mSensorRect.left);
+            setLayoutParams(lp);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 951a6ae..ab9b647 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -28,6 +28,7 @@
 import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
+import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Point;
@@ -74,7 +75,6 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.ViewController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
 import java.io.PrintWriter;
@@ -90,7 +90,7 @@
  * icon will show a set distance from the bottom of the device.
  */
 @SysUISingleton
-public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
+public class LockIconViewController implements Dumpable {
     private static final String TAG = "LockIconViewController";
     private static final float sDefaultDensity =
             (float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
@@ -109,6 +109,8 @@
     @NonNull private final ConfigurationController mConfigurationController;
     @NonNull private final DelayableExecutor mExecutor;
     private boolean mUdfpsEnrolled;
+    private Resources mResources;
+    private Context mContext;
 
     @NonNull private final AnimatedStateListDrawable mIcon;
 
@@ -120,6 +122,7 @@
     @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     @NonNull private final KeyguardTransitionInteractor mTransitionInteractor;
     @NonNull private final KeyguardInteractor mKeyguardInteractor;
+    @NonNull private final View.AccessibilityDelegate mAccessibilityDelegate;
 
     // Tracks the velocity of a touch to help filter out the touches that move too fast.
     private VelocityTracker mVelocityTracker;
@@ -154,6 +157,7 @@
 
     private boolean mDownDetected;
     private final Rect mSensorTouchLocation = new Rect();
+    private LockIconView mView;
 
     @VisibleForTesting
     final Consumer<TransitionStep> mDozeTransitionCallback = (TransitionStep step) -> {
@@ -178,7 +182,6 @@
 
     @Inject
     public LockIconViewController(
-            @Nullable LockIconView view,
             @NonNull StatusBarStateController statusBarStateController,
             @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
             @NonNull KeyguardViewController keyguardViewController,
@@ -195,9 +198,9 @@
             @NonNull KeyguardTransitionInteractor transitionInteractor,
             @NonNull KeyguardInteractor keyguardInteractor,
             @NonNull FeatureFlags featureFlags,
-            PrimaryBouncerInteractor primaryBouncerInteractor
+            PrimaryBouncerInteractor primaryBouncerInteractor,
+            Context context
     ) {
-        super(view);
         mStatusBarStateController = statusBarStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mAuthController = authController;
@@ -218,16 +221,40 @@
         mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
 
         mIcon = (AnimatedStateListDrawable)
-                resources.getDrawable(R.drawable.super_lock_icon, mView.getContext().getTheme());
-        mView.setImageDrawable(mIcon);
+                resources.getDrawable(R.drawable.super_lock_icon, context.getTheme());
         mUnlockedLabel = resources.getString(R.string.accessibility_unlock_button);
         mLockedLabel = resources.getString(R.string.accessibility_lock_icon);
         mLongPressTimeout = resources.getInteger(R.integer.config_lockIconLongPress);
         dumpManager.registerDumpable(TAG, this);
+        mResources = resources;
+        mContext = context;
+
+        mAccessibilityDelegate = new View.AccessibilityDelegate() {
+            private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint =
+                    new AccessibilityNodeInfo.AccessibilityAction(
+                            AccessibilityNodeInfoCompat.ACTION_CLICK,
+                            mResources.getString(R.string.accessibility_authenticate_hint));
+            private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityEnterHint =
+                    new AccessibilityNodeInfo.AccessibilityAction(
+                            AccessibilityNodeInfoCompat.ACTION_CLICK,
+                            mResources.getString(R.string.accessibility_enter_hint));
+            public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(v, info);
+                if (isActionable()) {
+                    if (mShowLockIcon) {
+                        info.addAction(mAccessibilityAuthenticateHint);
+                    } else if (mShowUnlockIcon) {
+                        info.addAction(mAccessibilityEnterHint);
+                    }
+                }
+            }
+        };
     }
 
-    @Override
-    protected void onInit() {
+    /** Sets the LockIconView to the controller and rebinds any that depend on it. */
+    public void setLockIconView(LockIconView lockIconView) {
+        mView = lockIconView;
+        mView.setImageDrawable(mIcon);
         mView.setAccessibilityDelegate(mAccessibilityDelegate);
 
         if (mFeatureFlags.isEnabled(DOZING_MIGRATION_1)) {
@@ -240,10 +267,7 @@
             collectFlow(mView, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
                     mIsActiveDreamLockscreenHostedCallback);
         }
-    }
 
-    @Override
-    protected void onViewAttached() {
         updateIsUdfpsEnrolled();
         updateConfiguration();
         updateKeyguardShowing();
@@ -256,19 +280,49 @@
         mStatusBarState = mStatusBarStateController.getState();
 
         updateColors();
-        mConfigurationController.addCallback(mConfigurationListener);
-
-        mAuthController.addCallback(mAuthControllerCallback);
-        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
-        mStatusBarStateController.addCallback(mStatusBarStateListener);
-        mKeyguardStateController.addCallback(mKeyguardStateCallback);
         mDownDetected = false;
         updateBurnInOffsets();
         updateVisibility();
 
+        updateAccessibility();
+
+        lockIconView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View view) {
+                registerCallbacks();
+            }
+
+            @Override
+            public void onViewDetachedFromWindow(View view) {
+                unregisterCallbacks();
+            }
+        });
+
+        if (lockIconView.isAttachedToWindow()) {
+            registerCallbacks();
+        }
+    }
+
+    private void registerCallbacks() {
+        mConfigurationController.addCallback(mConfigurationListener);
+        mAuthController.addCallback(mAuthControllerCallback);
+        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+        mStatusBarStateController.addCallback(mStatusBarStateListener);
+        mKeyguardStateController.addCallback(mKeyguardStateCallback);
         mAccessibilityManager.addAccessibilityStateChangeListener(
                 mAccessibilityStateChangeListener);
-        updateAccessibility();
+
+    }
+
+    private void unregisterCallbacks() {
+        mAuthController.removeCallback(mAuthControllerCallback);
+        mConfigurationController.removeCallback(mConfigurationListener);
+        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+        mStatusBarStateController.removeCallback(mStatusBarStateListener);
+        mKeyguardStateController.removeCallback(mKeyguardStateCallback);
+        mAccessibilityManager.removeAccessibilityStateChangeListener(
+                mAccessibilityStateChangeListener);
+
     }
 
     private void updateAccessibility() {
@@ -279,18 +333,6 @@
         }
     }
 
-    @Override
-    protected void onViewDetached() {
-        mAuthController.removeCallback(mAuthControllerCallback);
-        mConfigurationController.removeCallback(mConfigurationListener);
-        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
-        mStatusBarStateController.removeCallback(mStatusBarStateListener);
-        mKeyguardStateController.removeCallback(mKeyguardStateCallback);
-
-        mAccessibilityManager.removeAccessibilityStateChangeListener(
-                mAccessibilityStateChangeListener);
-    }
-
     public float getTop() {
         return mView.getLocationTop();
     }
@@ -363,28 +405,6 @@
         }
     }
 
-    private final View.AccessibilityDelegate mAccessibilityDelegate =
-            new View.AccessibilityDelegate() {
-        private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint =
-                new AccessibilityNodeInfo.AccessibilityAction(
-                        AccessibilityNodeInfoCompat.ACTION_CLICK,
-                        getResources().getString(R.string.accessibility_authenticate_hint));
-        private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityEnterHint =
-                new AccessibilityNodeInfo.AccessibilityAction(
-                        AccessibilityNodeInfoCompat.ACTION_CLICK,
-                        getResources().getString(R.string.accessibility_enter_hint));
-        public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(v, info);
-            if (isActionable()) {
-                if (mShowLockIcon) {
-                    info.addAction(mAccessibilityAuthenticateHint);
-                } else if (mShowUnlockIcon) {
-                    info.addAction(mAccessibilityEnterHint);
-                }
-            }
-        }
-    };
-
     private boolean isLockScreen() {
         return !mIsDozing
                 && !mIsBouncerShowing
@@ -401,18 +421,15 @@
     }
 
     private void updateConfiguration() {
-        WindowManager windowManager = getContext().getSystemService(WindowManager.class);
+        WindowManager windowManager = mContext.getSystemService(WindowManager.class);
         Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
         mWidthPixels = bounds.right;
         mHeightPixels = bounds.bottom;
-        mBottomPaddingPx = getResources().getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
-        mDefaultPaddingPx =
-                getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
-
-        mUnlockedLabel = mView.getContext().getResources().getString(
+        mBottomPaddingPx = mResources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
+        mDefaultPaddingPx = mResources.getDimensionPixelSize(R.dimen.lock_icon_padding);
+        mUnlockedLabel = mResources.getString(
                 R.string.accessibility_unlock_button);
-        mLockedLabel = mView.getContext()
-                .getResources().getString(R.string.accessibility_lock_icon);
+        mLockedLabel = mResources.getString(R.string.accessibility_lock_icon);
         updateLockIconLocation();
     }
 
@@ -755,7 +772,7 @@
         } else {
             mVibrator.vibrate(
                     Process.myUid(),
-                    getContext().getOpPackageName(),
+                    mContext.getOpPackageName(),
                     UdfpsController.EFFECT_CLICK,
                     "lock-icon-down",
                     TOUCH_VIBRATION_ATTRIBUTES);
@@ -769,7 +786,7 @@
         } else {
             mVibrator.vibrate(
                     Process.myUid(),
-                    getContext().getOpPackageName(),
+                    mContext.getOpPackageName(),
                     UdfpsController.EFFECT_CLICK,
                     "lock-screen-lock-icon-longpress",
                     TOUCH_VIBRATION_ATTRIBUTES);
diff --git a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
index 8e8ee48..9a2ffe0 100644
--- a/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PasswordTextView.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -11,7 +11,7 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.keyguard;
@@ -30,18 +30,11 @@
 import android.graphics.Typeface;
 import android.os.PowerManager;
 import android.os.SystemClock;
-import android.text.InputType;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
-import android.widget.EditText;
-import android.widget.FrameLayout;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
@@ -52,12 +45,11 @@
  * A View similar to a textView which contains password text and can animate when the text is
  * changed
  */
-public class PasswordTextView extends FrameLayout {
-
-    private static final float DOT_OVERSHOOT_FACTOR = 1.5f;
-    private static final long DOT_APPEAR_DURATION_OVERSHOOT = 320;
+public class PasswordTextView extends BasePasswordTextView {
     public static final long APPEAR_DURATION = 160;
     public static final long DISAPPEAR_DURATION = 160;
+    private static final float DOT_OVERSHOOT_FACTOR = 1.5f;
+    private static final long DOT_APPEAR_DURATION_OVERSHOOT = 320;
     private static final long RESET_DELAY_PER_ELEMENT = 40;
     private static final long RESET_MAX_DELAY = 200;
 
@@ -82,15 +74,12 @@
      */
     private static final float OVERSHOOT_TIME_POSITION = 0.5f;
 
-    private static char DOT = '\u2022';
-
     /**
      * The raw text size, will be multiplied by the scaled density when drawn
      */
     private int mTextHeightRaw;
     private final int mGravity;
     private ArrayList<CharState> mTextChars = new ArrayList<>();
-    private String mText = "";
     private int mDotSize;
     private PowerManager mPM;
     private int mCharPadding;
@@ -99,15 +88,6 @@
     private Interpolator mAppearInterpolator;
     private Interpolator mDisappearInterpolator;
     private Interpolator mFastOutSlowInInterpolator;
-    private boolean mShowPassword = true;
-    private UserActivityListener mUserActivityListener;
-    private boolean mIsPinHinting;
-    private PinShapeInput mPinShapeInput;
-    private boolean mUsePinShapes = false;
-
-    public interface UserActivityListener {
-        void onUserActivity();
-    }
 
     public PasswordTextView(Context context) {
         this(context, null);
@@ -145,8 +125,7 @@
             mCharPadding = a.getDimensionPixelSize(R.styleable.PasswordTextView_charPadding,
                     getContext().getResources().getDimensionPixelSize(
                             R.dimen.password_char_padding));
-            mDrawColor = a.getColor(R.styleable.PasswordTextView_android_textColor,
-                    Color.WHITE);
+            mDrawColor = a.getColor(R.styleable.PasswordTextView_android_textColor, Color.WHITE);
             mDrawPaint.setColor(mDrawColor);
 
         } finally {
@@ -156,8 +135,7 @@
         mDrawPaint.setFlags(Paint.SUBPIXEL_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG);
         mDrawPaint.setTextAlign(Paint.Align.CENTER);
         mDrawPaint.setTypeface(Typeface.create(
-                context.getString(com.android.internal.R.string.config_headlineFontFamily),
-                0));
+                context.getString(com.android.internal.R.string.config_headlineFontFamily), 0));
         mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
                 android.R.interpolator.linear_out_slow_in);
         mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
@@ -169,9 +147,19 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        mTextHeightRaw = getContext().getResources().getInteger(
-                R.integer.scaled_password_text_size);
+    protected PinShapeInput inflatePinShapeInput(boolean isPinHinting) {
+        if (isPinHinting) {
+            return (PinShapeInput) LayoutInflater.from(mContext).inflate(
+                    R.layout.keyguard_pin_shape_hinting_view, null);
+        } else {
+            return (PinShapeInput) LayoutInflater.from(mContext).inflate(
+                    R.layout.keyguard_pin_shape_non_hinting_view, null);
+        }
+    }
+
+    @Override
+    protected boolean shouldSendAccessibilityEvent() {
+        return isFocused() || isSelected() && isShown();
     }
 
     @Override
@@ -201,8 +189,8 @@
         int charHeight = (bounds.bottom - bounds.top);
         float yPosition =
                 (getHeight() - getPaddingBottom() - getPaddingTop()) / 2 + getPaddingTop();
-        canvas.clipRect(getPaddingLeft(), getPaddingTop(),
-                getWidth() - getPaddingRight(), getHeight() - getPaddingBottom());
+        canvas.clipRect(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(),
+                getHeight() - getPaddingBottom());
         float charLength = bounds.right - bounds.left;
         for (int i = 0; i < length; i++) {
             CharState charState = mTextChars.get(i);
@@ -212,6 +200,67 @@
         }
     }
 
+    @Override
+    protected void onAppend(char c, int newLength) {
+        int visibleChars = mTextChars.size();
+        CharState charState;
+        if (newLength > visibleChars) {
+            charState = obtainCharState(c);
+            mTextChars.add(charState);
+        } else {
+            charState = mTextChars.get(newLength - 1);
+            charState.whichChar = c;
+        }
+        charState.startAppearAnimation();
+
+        // ensure that the previous element is being swapped
+        if (newLength > 1) {
+            CharState previousState = mTextChars.get(newLength - 2);
+            if (previousState.isDotSwapPending) {
+                previousState.swapToDotWhenAppearFinished();
+            }
+        }
+    }
+
+    @Override
+    protected void onDelete(int index) {
+        CharState charState = mTextChars.get(index);
+        charState.startRemoveAnimation(0, 0);
+    }
+
+    @Override
+    protected void onReset(boolean animated) {
+        if (animated) {
+            int length = mTextChars.size();
+            int middleIndex = (length - 1) / 2;
+            long delayPerElement = RESET_DELAY_PER_ELEMENT;
+            for (int i = 0; i < length; i++) {
+                CharState charState = mTextChars.get(i);
+                int delayIndex;
+                if (i <= middleIndex) {
+                    delayIndex = i * 2;
+                } else {
+                    int distToMiddle = i - middleIndex;
+                    delayIndex = (length - 1) - (distToMiddle - 1) * 2;
+                }
+                long startDelay = delayIndex * delayPerElement;
+                startDelay = Math.min(startDelay, RESET_MAX_DELAY);
+                long maxDelay = delayPerElement * (length - 1);
+                maxDelay = Math.min(maxDelay, RESET_MAX_DELAY) + DISAPPEAR_DURATION;
+                charState.startRemoveAnimation(startDelay, maxDelay);
+                charState.removeDotSwapCallbacks();
+            }
+        } else {
+            mTextChars.clear();
+        }
+    }
+
+    @Override
+    protected void onUserActivity() {
+        mPM.userActivity(SystemClock.uptimeMillis(), false);
+        super.onUserActivity();
+    }
+
     /**
      * Reload colors from resources.
      **/
@@ -225,8 +274,9 @@
     }
 
     @Override
-    public boolean hasOverlappingRendering() {
-        return false;
+    protected void onConfigurationChanged(Configuration newConfig) {
+        mTextHeightRaw = getContext().getResources().getInteger(
+                R.integer.scaled_password_text_size);
     }
 
     private Rect getCharBounds() {
@@ -252,67 +302,14 @@
         return width;
     }
 
-
-    public void append(char c) {
-        int visibleChars = mTextChars.size();
-        CharSequence textbefore = getTransformedText();
-        mText = mText + c;
-        int newLength = mText.length();
-        CharState charState;
-        if (newLength > visibleChars) {
-            charState = obtainCharState(c);
-            mTextChars.add(charState);
-        } else {
-            charState = mTextChars.get(newLength - 1);
-            charState.whichChar = c;
-        }
-        if (mPinShapeInput != null) {
-            mPinShapeInput.append();
-        }
-        charState.startAppearAnimation();
-
-        // ensure that the previous element is being swapped
-        if (newLength > 1) {
-            CharState previousState = mTextChars.get(newLength - 2);
-            if (previousState.isDotSwapPending) {
-                previousState.swapToDotWhenAppearFinished();
-            }
-        }
-        userActivity();
-        sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length(), 0, 1);
+    private CharState obtainCharState(char c) {
+        CharState charState = new CharState();
+        charState.whichChar = c;
+        return charState;
     }
 
-    public void setUserActivityListener(UserActivityListener userActivityListener) {
-        mUserActivityListener = userActivityListener;
-    }
-
-    private void userActivity() {
-        mPM.userActivity(SystemClock.uptimeMillis(), false);
-        if (mUserActivityListener != null) {
-            mUserActivityListener.onUserActivity();
-        }
-    }
-
-    public void deleteLastChar() {
-        int length = mText.length();
-        CharSequence textbefore = getTransformedText();
-        if (length > 0) {
-            mText = mText.substring(0, length - 1);
-            CharState charState = mTextChars.get(length - 1);
-            charState.startRemoveAnimation(0, 0);
-            sendAccessibilityEventTypeViewTextChanged(textbefore, textbefore.length() - 1, 1, 0);
-            if (mPinShapeInput != null) {
-                mPinShapeInput.delete();
-            }
-        }
-        userActivity();
-    }
-
-    public String getText() {
-        return mText;
-    }
-
-    private CharSequence getTransformedText() {
+    @Override
+    protected CharSequence getTransformedText() {
         int textLength = mTextChars.size();
         StringBuilder stringBuilder = new StringBuilder(textLength);
         for (int i = 0; i < textLength; i++) {
@@ -327,130 +324,6 @@
         return stringBuilder;
     }
 
-    private CharState obtainCharState(char c) {
-        CharState charState = new CharState();
-        charState.whichChar = c;
-        return charState;
-    }
-
-    public void reset(boolean animated, boolean announce) {
-        CharSequence textbefore = getTransformedText();
-        mText = "";
-        int length = mTextChars.size();
-        int middleIndex = (length - 1) / 2;
-        long delayPerElement = RESET_DELAY_PER_ELEMENT;
-        for (int i = 0; i < length; i++) {
-            CharState charState = mTextChars.get(i);
-            if (animated) {
-                int delayIndex;
-                if (i <= middleIndex) {
-                    delayIndex = i * 2;
-                } else {
-                    int distToMiddle = i - middleIndex;
-                    delayIndex = (length - 1) - (distToMiddle - 1) * 2;
-                }
-                long startDelay = delayIndex * delayPerElement;
-                startDelay = Math.min(startDelay, RESET_MAX_DELAY);
-                long maxDelay = delayPerElement * (length - 1);
-                maxDelay = Math.min(maxDelay, RESET_MAX_DELAY) + DISAPPEAR_DURATION;
-                charState.startRemoveAnimation(startDelay, maxDelay);
-                charState.removeDotSwapCallbacks();
-            }
-        }
-        if (!animated) {
-            mTextChars.clear();
-        } else {
-            userActivity();
-        }
-        if (mPinShapeInput != null) {
-            mPinShapeInput.reset();
-        }
-        if (announce) {
-            sendAccessibilityEventTypeViewTextChanged(textbefore, 0, textbefore.length(), 0);
-        }
-    }
-
-    void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText, int fromIndex,
-                                                   int removedCount, int addedCount) {
-        if (AccessibilityManager.getInstance(mContext).isEnabled() &&
-                (isFocused() || isSelected() && isShown())) {
-            AccessibilityEvent event =
-                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
-            event.setFromIndex(fromIndex);
-            event.setRemovedCount(removedCount);
-            event.setAddedCount(addedCount);
-            event.setBeforeText(beforeText);
-            CharSequence transformedText = getTransformedText();
-            if (!TextUtils.isEmpty(transformedText)) {
-                event.getText().add(transformedText);
-            }
-            event.setPassword(true);
-            sendAccessibilityEventUnchecked(event);
-        }
-    }
-
-    @Override
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-
-        event.setClassName(EditText.class.getName());
-        event.setPassword(true);
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-
-        info.setClassName(EditText.class.getName());
-        info.setPassword(true);
-        info.setText(getTransformedText());
-
-        info.setEditable(true);
-
-        info.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-    }
-
-    /**
-     * Sets whether to use pin shapes.
-     */
-    public void setUsePinShapes(boolean usePinShapes) {
-        mUsePinShapes = usePinShapes;
-    }
-
-    /**
-     * Determines whether AutoConfirmation feature is on.
-     *
-     * @param isPinHinting
-     */
-    public void setIsPinHinting(boolean isPinHinting) {
-        // Do not reinflate the view if we are using the same one.
-        if (mPinShapeInput != null && mIsPinHinting == isPinHinting) {
-            return;
-        }
-        mIsPinHinting = isPinHinting;
-
-        if (mPinShapeInput != null) {
-            removeView(mPinShapeInput.getView());
-            mPinShapeInput = null;
-        }
-
-        if (isPinHinting) {
-            mPinShapeInput = (PinShapeInput) LayoutInflater.from(mContext).inflate(
-                    R.layout.keyguard_pin_shape_hinting_view, null);
-        } else {
-            mPinShapeInput = (PinShapeInput) LayoutInflater.from(mContext).inflate(
-                    R.layout.keyguard_pin_shape_non_hinting_view, null);
-        }
-        addView(mPinShapeInput.getView());
-    }
-
-    /**
-     * Controls whether the last entered digit is briefly shown after being entered
-     */
-    public void setShowPassword(boolean enabled) {
-        mShowPassword = enabled;
-    }
-
     private class CharState {
         char whichChar;
         ValueAnimator textAnimator;
@@ -468,6 +341,7 @@
 
         Animator.AnimatorListener removeEndListener = new AnimatorListenerAdapter() {
             private boolean mCancelled;
+
             @Override
             public void onAnimationCancel(Animator animation) {
                 mCancelled = true;
@@ -516,53 +390,53 @@
             }
         };
 
-        private ValueAnimator.AnimatorUpdateListener dotSizeUpdater
-                = new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                currentDotSizeFactor = (float) animation.getAnimatedValue();
-                invalidate();
-            }
-        };
-
-        private ValueAnimator.AnimatorUpdateListener textSizeUpdater
-                = new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                boolean textVisibleBefore = isCharVisibleForA11y();
-                float beforeTextSizeFactor = currentTextSizeFactor;
-                currentTextSizeFactor = (float) animation.getAnimatedValue();
-                if (textVisibleBefore != isCharVisibleForA11y()) {
-                    currentTextSizeFactor = beforeTextSizeFactor;
-                    CharSequence beforeText = getTransformedText();
-                    currentTextSizeFactor = (float) animation.getAnimatedValue();
-                    int indexOfThisChar = mTextChars.indexOf(CharState.this);
-                    if (indexOfThisChar >= 0) {
-                        sendAccessibilityEventTypeViewTextChanged(
-                                beforeText, indexOfThisChar, 1, 1);
+        private ValueAnimator.AnimatorUpdateListener mDotSizeUpdater =
+                new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        currentDotSizeFactor = (float) animation.getAnimatedValue();
+                        invalidate();
                     }
-                }
-                invalidate();
-            }
-        };
+                };
 
-        private ValueAnimator.AnimatorUpdateListener textTranslationUpdater
-                = new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                currentTextTranslationY = (float) animation.getAnimatedValue();
-                invalidate();
-            }
-        };
+        private ValueAnimator.AnimatorUpdateListener mTextSizeUpdater =
+                new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        boolean textVisibleBefore = isCharVisibleForA11y();
+                        float beforeTextSizeFactor = currentTextSizeFactor;
+                        currentTextSizeFactor = (float) animation.getAnimatedValue();
+                        if (textVisibleBefore != isCharVisibleForA11y()) {
+                            currentTextSizeFactor = beforeTextSizeFactor;
+                            CharSequence beforeText = getTransformedText();
+                            currentTextSizeFactor = (float) animation.getAnimatedValue();
+                            int indexOfThisChar = mTextChars.indexOf(CharState.this);
+                            if (indexOfThisChar >= 0) {
+                                sendAccessibilityEventTypeViewTextChanged(beforeText,
+                                        indexOfThisChar, 1, 1);
+                            }
+                        }
+                        invalidate();
+                    }
+                };
 
-        private ValueAnimator.AnimatorUpdateListener widthUpdater
-                = new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                currentWidthFactor = (float) animation.getAnimatedValue();
-                invalidate();
-            }
-        };
+        private ValueAnimator.AnimatorUpdateListener mTextTranslationUpdater =
+                new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        currentTextTranslationY = (float) animation.getAnimatedValue();
+                        invalidate();
+                    }
+                };
+
+        private ValueAnimator.AnimatorUpdateListener mWidthUpdater =
+                new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        currentWidthFactor = (float) animation.getAnimatedValue();
+                        invalidate();
+                    }
+                };
 
         private Runnable dotSwapperRunnable = new Runnable() {
             @Override
@@ -573,12 +447,15 @@
         };
 
         void startRemoveAnimation(long startDelay, long widthDelay) {
-            boolean dotNeedsAnimation = (currentDotSizeFactor > 0.0f && dotAnimator == null)
-                    || (dotAnimator != null && dotAnimationIsGrowing);
-            boolean textNeedsAnimation = (currentTextSizeFactor > 0.0f && textAnimator == null)
-                    || (textAnimator != null && textAnimationIsGrowing);
-            boolean widthNeedsAnimation = (currentWidthFactor > 0.0f && widthAnimator == null)
-                    || (widthAnimator != null && widthAnimationIsGrowing);
+            boolean dotNeedsAnimation =
+                    (currentDotSizeFactor > 0.0f && dotAnimator == null) || (dotAnimator != null
+                            && dotAnimationIsGrowing);
+            boolean textNeedsAnimation =
+                    (currentTextSizeFactor > 0.0f && textAnimator == null) || (textAnimator != null
+                            && textAnimationIsGrowing);
+            boolean widthNeedsAnimation =
+                    (currentWidthFactor > 0.0f && widthAnimator == null) || (widthAnimator != null
+                            && widthAnimationIsGrowing);
             if (dotNeedsAnimation) {
                 startDotDisappearAnimation(startDelay);
             }
@@ -591,10 +468,10 @@
         }
 
         void startAppearAnimation() {
-            boolean dotNeedsAnimation = !mShowPassword
-                    && (dotAnimator == null || !dotAnimationIsGrowing);
-            boolean textNeedsAnimation = mShowPassword
-                    && (textAnimator == null || !textAnimationIsGrowing);
+            boolean dotNeedsAnimation =
+                    !mShowPassword && (dotAnimator == null || !dotAnimationIsGrowing);
+            boolean textNeedsAnimation =
+                    mShowPassword && (textAnimator == null || !textAnimationIsGrowing);
             boolean widthNeedsAnimation = (widthAnimator == null || !widthAnimationIsGrowing);
             if (dotNeedsAnimation) {
                 startDotAppearAnimation(0);
@@ -628,8 +505,8 @@
         void swapToDotWhenAppearFinished() {
             removeDotSwapCallbacks();
             if (textAnimator != null) {
-                long remainingDuration = textAnimator.getDuration()
-                        - textAnimator.getCurrentPlayTime();
+                long remainingDuration =
+                        textAnimator.getDuration() - textAnimator.getCurrentPlayTime();
                 postDotSwap(remainingDuration + TEXT_REST_DURATION_AFTER_APPEAR);
             } else {
                 performSwap();
@@ -638,14 +515,14 @@
 
         private void performSwap() {
             startTextDisappearAnimation(0);
-            startDotAppearAnimation(DISAPPEAR_DURATION
-                    - DOT_APPEAR_TEXT_DISAPPEAR_OVERLAP_DURATION);
+            startDotAppearAnimation(
+                    DISAPPEAR_DURATION - DOT_APPEAR_TEXT_DISAPPEAR_OVERLAP_DURATION);
         }
 
         private void startWidthDisappearAnimation(long widthDelay) {
             cancelAnimator(widthAnimator);
             widthAnimator = ValueAnimator.ofFloat(currentWidthFactor, 0.0f);
-            widthAnimator.addUpdateListener(widthUpdater);
+            widthAnimator.addUpdateListener(mWidthUpdater);
             widthAnimator.addListener(widthFinishListener);
             widthAnimator.addListener(removeEndListener);
             widthAnimator.setDuration((long) (DISAPPEAR_DURATION * currentWidthFactor));
@@ -657,7 +534,7 @@
         private void startTextDisappearAnimation(long startDelay) {
             cancelAnimator(textAnimator);
             textAnimator = ValueAnimator.ofFloat(currentTextSizeFactor, 0.0f);
-            textAnimator.addUpdateListener(textSizeUpdater);
+            textAnimator.addUpdateListener(mTextSizeUpdater);
             textAnimator.addListener(textFinishListener);
             textAnimator.setInterpolator(mDisappearInterpolator);
             textAnimator.setDuration((long) (DISAPPEAR_DURATION * currentTextSizeFactor));
@@ -669,7 +546,7 @@
         private void startDotDisappearAnimation(long startDelay) {
             cancelAnimator(dotAnimator);
             ValueAnimator animator = ValueAnimator.ofFloat(currentDotSizeFactor, 0.0f);
-            animator.addUpdateListener(dotSizeUpdater);
+            animator.addUpdateListener(mDotSizeUpdater);
             animator.addListener(dotFinishListener);
             animator.setInterpolator(mDisappearInterpolator);
             long duration = (long) (DISAPPEAR_DURATION * Math.min(currentDotSizeFactor, 1.0f));
@@ -683,7 +560,7 @@
         private void startWidthAppearAnimation() {
             cancelAnimator(widthAnimator);
             widthAnimator = ValueAnimator.ofFloat(currentWidthFactor, 1.0f);
-            widthAnimator.addUpdateListener(widthUpdater);
+            widthAnimator.addUpdateListener(mWidthUpdater);
             widthAnimator.addListener(widthFinishListener);
             widthAnimator.setDuration((long) (APPEAR_DURATION * (1f - currentWidthFactor)));
             widthAnimator.start();
@@ -693,7 +570,7 @@
         private void startTextAppearAnimation() {
             cancelAnimator(textAnimator);
             textAnimator = ValueAnimator.ofFloat(currentTextSizeFactor, 1.0f);
-            textAnimator.addUpdateListener(textSizeUpdater);
+            textAnimator.addUpdateListener(mTextSizeUpdater);
             textAnimator.addListener(textFinishListener);
             textAnimator.setInterpolator(mAppearInterpolator);
             textAnimator.setDuration((long) (APPEAR_DURATION * (1f - currentTextSizeFactor)));
@@ -703,7 +580,7 @@
             // handle translation
             if (textTranslateAnimator == null) {
                 textTranslateAnimator = ValueAnimator.ofFloat(1.0f, 0.0f);
-                textTranslateAnimator.addUpdateListener(textTranslationUpdater);
+                textTranslateAnimator.addUpdateListener(mTextTranslationUpdater);
                 textTranslateAnimator.addListener(textTranslateFinishListener);
                 textTranslateAnimator.setInterpolator(mAppearInterpolator);
                 textTranslateAnimator.setDuration(APPEAR_DURATION);
@@ -717,14 +594,14 @@
                 // We perform an overshoot animation
                 ValueAnimator overShootAnimator = ValueAnimator.ofFloat(currentDotSizeFactor,
                         DOT_OVERSHOOT_FACTOR);
-                overShootAnimator.addUpdateListener(dotSizeUpdater);
+                overShootAnimator.addUpdateListener(mDotSizeUpdater);
                 overShootAnimator.setInterpolator(mAppearInterpolator);
-                long overShootDuration = (long) (DOT_APPEAR_DURATION_OVERSHOOT
-                        * OVERSHOOT_TIME_POSITION);
+                long overShootDuration =
+                        (long) (DOT_APPEAR_DURATION_OVERSHOOT * OVERSHOOT_TIME_POSITION);
                 overShootAnimator.setDuration(overShootDuration);
                 ValueAnimator settleBackAnimator = ValueAnimator.ofFloat(DOT_OVERSHOOT_FACTOR,
                         1.0f);
-                settleBackAnimator.addUpdateListener(dotSizeUpdater);
+                settleBackAnimator.addUpdateListener(mDotSizeUpdater);
                 settleBackAnimator.setDuration(DOT_APPEAR_DURATION_OVERSHOOT - overShootDuration);
                 settleBackAnimator.addListener(dotFinishListener);
                 AnimatorSet animatorSet = new AnimatorSet();
@@ -734,7 +611,7 @@
                 dotAnimator = animatorSet;
             } else {
                 ValueAnimator growAnimator = ValueAnimator.ofFloat(currentDotSizeFactor, 1.0f);
-                growAnimator.addUpdateListener(dotSizeUpdater);
+                growAnimator.addUpdateListener(mDotSizeUpdater);
                 growAnimator.setDuration((long) (APPEAR_DURATION * (1.0f - currentDotSizeFactor)));
                 growAnimator.addListener(dotFinishListener);
                 growAnimator.setStartDelay(delay);
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index 56c0953..5f33ef9 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -61,7 +61,7 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        if (getChildCount() > 0) {
+        if (getChildCount() > 2) {
             View firstChild = getChildAt(0);
             boolean isVisible = firstChild.getLocalVisibleRect(mFirstChildVisibleRect);
             boolean clipped = mFirstChildVisibleRect.left > 0
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
index 8dbe5e0..d59f51f 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
@@ -24,7 +24,7 @@
 import javax.inject.Scope;
 
 /**
- * Scope annotation for singleton items within the CentralSurfacesComponent.
+ * Scope annotation for singleton items within the {@link KeyguardBouncerComponent}.
  */
 @Documented
 @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java
index f498ef3..394d63171 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java
@@ -24,7 +24,7 @@
 import javax.inject.Scope;
 
 /**
- * Scope annotation for singleton items within the CentralSurfacesComponent.
+ * Scope annotation for singleton items within the {@link KeyguardStatusBarViewComponent}.
  */
 @Documented
 @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
index aeae8e3..6c2c9f2 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
@@ -24,7 +24,7 @@
 import javax.inject.Scope;
 
 /**
- * Scope annotation for singleton items within the CentralSurfacesComponent.
+ * Scope annotation for singleton items within the {@link KeyguardStatusViewComponent}.
  */
 @Documented
 @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index f29077d..e1612b0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -38,7 +38,7 @@
 import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
-import com.android.systemui.aconfig.Flags;
+import com.android.systemui.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
index 3822936..df2c05d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
@@ -34,8 +34,8 @@
 
 import androidx.annotation.DimenRes;
 
+import com.android.systemui.Flags;
 import com.android.systemui.R;
-import com.android.systemui.aconfig.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
index cc18c30..1f54952 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
@@ -24,7 +24,7 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
-import com.android.systemui.aconfig.Flags;
+import com.android.systemui.Flags;
 import com.android.systemui.util.settings.SecureSettings;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt b/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
index 251a699..fa61bba 100644
--- a/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/aconfig/AConfigModule.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.aconfig
 
+import com.android.systemui.FeatureFlags
+import com.android.systemui.FeatureFlagsImpl
 import com.android.systemui.dagger.SysUISingleton
 import dagger.Module
 import dagger.Provides
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index eec16e6..c9801d7 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -52,6 +52,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.inject.Inject;
@@ -184,6 +185,10 @@
     protected void setListening(boolean listening) {
         mListening = listening;
         if (listening) {
+            // System UI could be restarted while ops are active, so fetch the currently active ops
+            // once System UI starts listening again.
+            fetchCurrentActiveOps();
+
             mAppOps.startWatchingActive(OPS, this);
             mAppOps.startWatchingNoted(OPS, this);
             mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
@@ -216,6 +221,29 @@
         }
     }
 
+    private void fetchCurrentActiveOps() {
+        List<AppOpsManager.PackageOps> packageOps = mAppOps.getPackagesForOps(OPS);
+        for (AppOpsManager.PackageOps op : packageOps) {
+            for (AppOpsManager.OpEntry entry : op.getOps()) {
+                for (Map.Entry<String, AppOpsManager.AttributedOpEntry> attributedOpEntry :
+                        entry.getAttributedOpEntries().entrySet()) {
+                    if (attributedOpEntry.getValue().isRunning()) {
+                        onOpActiveChanged(
+                                entry.getOpStr(),
+                                op.getUid(),
+                                op.getPackageName(),
+                                /* attributionTag= */ attributedOpEntry.getKey(),
+                                /* active= */ true,
+                                // AppOpsManager doesn't have a way to fetch attribution flags or
+                                // chain ID given an op entry, so default them to none.
+                                AppOpsManager.ATTRIBUTION_FLAGS_NONE,
+                                AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Adds a callback that will get notifified when an AppOp of the type the controller tracks
      * changes
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 165bb6c..f26404ca 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -154,12 +154,12 @@
             new IVisualQueryDetectionAttentionListener.Stub() {
         @Override
         public void onAttentionGained() {
-            mVisualQueryAttentionListeners.forEach(VisualQueryAttentionListener::onAttentionGained);
+            handleVisualAttentionChanged(true);
         }
 
         @Override
         public void onAttentionLost() {
-            mVisualQueryAttentionListeners.forEach(VisualQueryAttentionListener::onAttentionLost);
+            handleVisualAttentionChanged(false);
         }
     };
 
@@ -433,11 +433,21 @@
 
                     @Override
                     public void onStopPerceiving() {
+                        // Treat this as a signal that attention has been lost (and inform listeners
+                        // accordingly).
+                        handleVisualAttentionChanged(false);
                         mAssistUtils.disableVisualQueryDetection();
                     }
                 });
     }
 
+    private void handleVisualAttentionChanged(boolean attentionGained) {
+        mVisualQueryAttentionListeners.forEach(
+                attentionGained
+                        ? VisualQueryAttentionListener::onAttentionGained
+                        : VisualQueryAttentionListener::onAttentionLost);
+    }
+
     public void launchVoiceAssistFromKeyguard() {
         mAssistUtils.launchVoiceAssistFromKeyguard();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
index 3c74bf4..066cba23 100644
--- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
@@ -16,24 +16,69 @@
 
 package com.android.systemui.back.domain.interactor
 
+import android.window.BackEvent
+import android.window.OnBackAnimationCallback
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
+import android.window.WindowOnBackInvokedDispatcher
+import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
 import com.android.systemui.shade.QuickSettingsController
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 /** Handles requests to go back either from a button or gesture. */
 @SysUISingleton
 class BackActionInteractor
 @Inject
 constructor(
+    @Application private val scope: CoroutineScope,
     private val statusBarStateController: StatusBarStateController,
     private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
-    private val shadeController: ShadeController
-) {
+    private val shadeController: ShadeController,
+    private val notificationShadeWindowController: NotificationShadeWindowController,
+    private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor,
+    featureFlags: FeatureFlags,
+) : CoreStartable {
+
+    private var isCallbackRegistered = false
+
+    private val callback =
+        if (featureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE)) {
+            /**
+             * New callback that handles back gesture invoked, cancel, progress and provides
+             * feedback via Shade animation.
+             */
+            object : OnBackAnimationCallback {
+                override fun onBackInvoked() {
+                    onBackRequested()
+                }
+
+                override fun onBackProgressed(backEvent: BackEvent) {
+                    if (shouldBackBeHandled() && shadeViewController.canBeCollapsed()) {
+                        shadeViewController.onBackProgressed(backEvent.progress)
+                    }
+                }
+            }
+        } else {
+            OnBackInvokedCallback { onBackRequested() }
+        }
+
+    private val onBackInvokedDispatcher: WindowOnBackInvokedDispatcher?
+        get() =
+            notificationShadeWindowController.windowRootView?.viewRootImpl?.onBackInvokedDispatcher
+
     private lateinit var shadeViewController: ShadeViewController
     private lateinit var qsController: QuickSettingsController
 
@@ -42,6 +87,19 @@
         this.shadeViewController = svController
     }
 
+    override fun start() {
+        scope.launch {
+            windowRootViewVisibilityInteractor.isLockscreenOrShadeVisibleAndInteractive.collect {
+                visible ->
+                if (visible) {
+                    registerBackCallback()
+                } else {
+                    unregisterBackCallback()
+                }
+            }
+        }
+    }
+
     fun shouldBackBeHandled(): Boolean {
         return statusBarStateController.state != StatusBarState.KEYGUARD &&
             statusBarStateController.state != StatusBarState.SHADE_LOCKED &&
@@ -74,4 +132,24 @@
         }
         return false
     }
+
+    private fun registerBackCallback() {
+        if (isCallbackRegistered) {
+            return
+        }
+        onBackInvokedDispatcher?.let {
+            it.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, callback)
+            isCallbackRegistered = true
+        }
+    }
+
+    private fun unregisterBackCallback() {
+        if (!isCallbackRegistered) {
+            return
+        }
+        onBackInvokedDispatcher?.let {
+            it.unregisterOnBackInvokedCallback(callback)
+            isCallbackRegistered = false
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 0ca3883..b6f47e9 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -31,6 +31,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -240,4 +241,50 @@
             }
         }
     }
+
+    /** */
+    @SysUISingleton
+    public static class Factory {
+        private final UserTracker mUserTracker;
+        private final ConfigurationController mConfigurationController;
+        private final TunerService mTunerService;
+        private final @Main Handler mMainHandler;
+        private final ContentResolver mContentResolver;
+        private final FeatureFlags mFeatureFlags;
+        private final BatteryController mBatteryController;
+
+        @Inject
+        public Factory(
+                UserTracker userTracker,
+                ConfigurationController configurationController,
+                TunerService tunerService,
+                @Main Handler mainHandler,
+                ContentResolver contentResolver,
+                FeatureFlags featureFlags,
+                BatteryController batteryController
+        ) {
+            mUserTracker = userTracker;
+            mConfigurationController = configurationController;
+            mTunerService = tunerService;
+            mMainHandler = mainHandler;
+            mContentResolver = contentResolver;
+            mFeatureFlags = featureFlags;
+            mBatteryController = batteryController;
+        }
+
+        /** */
+        public BatteryMeterViewController create(View view, StatusBarLocation location) {
+            return new BatteryMeterViewController(
+                    (BatteryMeterView) view,
+                    location,
+                    mUserTracker,
+                    mConfigurationController,
+                    mTunerService,
+                    mMainHandler,
+                    mContentResolver,
+                    mFeatureFlags,
+                    mBatteryController
+            );
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 0d7d9cc..017ac60 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -446,7 +446,9 @@
             for (key in listOf(".blue600", ".blue400")) {
                 addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
                     PorterDuffColorFilter(
-                        context.getColor(com.android.settingslib.R.color.settingslib_color_blue400),
+                        context.getColor(
+                            com.android.settingslib.color.R.color.settingslib_color_blue400
+                        ),
                         PorterDuff.Mode.SRC_ATOP
                     )
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index b23e085..a368703 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -586,16 +586,18 @@
                 if (shouldTryToDismissKeyguard()) {
                     tryDismissingKeyguard();
                 }
-                onFingerDown(requestId,
-                        data.getPointerId(),
-                        data.getX(),
-                        data.getY(),
-                        data.getMinor(),
-                        data.getMajor(),
-                        data.getOrientation(),
-                        data.getTime(),
-                        data.getGestureStart(),
-                        mStatusBarStateController.isDozing());
+                if (!mOnFingerDown) {
+                    onFingerDown(requestId,
+                            data.getPointerId(),
+                            data.getX(),
+                            data.getY(),
+                            data.getMinor(),
+                            data.getMajor(),
+                            data.getOrientation(),
+                            data.getTime(),
+                            data.getGestureStart(),
+                            mStatusBarStateController.isDozing());
+                }
 
                 // Pilfer if valid overlap, don't allow following events to reach keyguard
                 shouldPilfer = true;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index e8b8f54..be08932 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -78,17 +78,6 @@
 
     private val _isOverlayTouched: MutableStateFlow<Boolean> = MutableStateFlow(false)
 
-    /**
-     * If the API caller or the user's personal preferences require explicit confirmation after
-     * successful authentication.
-     */
-    val isConfirmationRequired: Flow<Boolean> =
-        combine(_isOverlayTouched, promptSelectorInteractor.isConfirmationRequired) {
-            isOverlayTouched,
-            isConfirmationRequired ->
-            !isOverlayTouched && isConfirmationRequired
-        }
-
     /** The kind of credential the user has. */
     val credentialKind: Flow<PromptKind> = promptSelectorInteractor.credentialKind
 
@@ -137,6 +126,15 @@
             }
             .distinctUntilChanged()
 
+    /**
+     * If the API caller or the user's personal preferences require explicit confirmation after
+     * successful authentication. Confirmation always required when in explicit flow.
+     */
+    val isConfirmationRequired: Flow<Boolean> =
+        combine(_isOverlayTouched, size) { isOverlayTouched, size ->
+            !isOverlayTouched && size.isNotSmall
+        }
+
     /** Title for the prompt. */
     val title: Flow<String> =
         promptSelectorInteractor.prompt.map { it?.title ?: "" }.distinctUntilChanged()
@@ -170,12 +168,7 @@
             .distinctUntilChanged()
 
     /** If the icon can be used as a confirmation button. */
-    val isIconConfirmButton: Flow<Boolean> =
-        combine(size, promptSelectorInteractor.isConfirmationRequired) {
-            size,
-            isConfirmationRequired ->
-            size.isNotSmall && isConfirmationRequired
-        }
+    val isIconConfirmButton: Flow<Boolean> = size.map { it.isNotSmall }.distinctUntilChanged()
 
     /** If the negative button should be shown. */
     val isNegativeButtonVisible: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 1bf3a9e..9527f32 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -22,11 +22,12 @@
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
 import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
 import com.android.systemui.bouncer.data.repository.BouncerRepository
+import com.android.systemui.classifier.FalsingClassifier
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.util.kotlin.pairwise
@@ -49,7 +50,8 @@
     private val repository: BouncerRepository,
     private val authenticationInteractor: AuthenticationInteractor,
     private val sceneInteractor: SceneInteractor,
-    featureFlags: FeatureFlags,
+    flags: SceneContainerFlags,
+    private val falsingInteractor: FalsingInteractor,
 ) {
 
     /** The user-facing message to show in the bouncer. */
@@ -91,7 +93,7 @@
     val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
 
     init {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (flags.isEnabled()) {
             // Clear the message if moved from throttling to no-longer throttling.
             applicationScope.launch {
                 isThrottled.pairwise().collect { (wasThrottled, currentlyThrottled) ->
@@ -103,6 +105,34 @@
         }
     }
 
+    /** Notifies that the user has places down a pointer, not necessarily dragging just yet. */
+    fun onDown() {
+        falsingInteractor.avoidGesture()
+    }
+
+    /**
+     * Notifies of "intentional" (i.e. non-false) user interaction with the UI which is very likely
+     * to be real user interaction with the bouncer and not the result of a false touch in the
+     * user's pocket or by the user's face while holding their device up to their ear.
+     */
+    fun onIntentionalUserInput() {
+        falsingInteractor.updateFalseConfidence(FalsingClassifier.Result.passed(0.6))
+    }
+
+    /**
+     * Notifies of false input which is very likely to be the result of a false touch in the user's
+     * pocket or by the user's face while holding their device up to their ear.
+     */
+    fun onFalseUserInput() {
+        falsingInteractor.updateFalseConfidence(
+            FalsingClassifier.Result.falsed(
+                /* confidence= */ 0.7,
+                /* context= */ javaClass.simpleName,
+                /* reason= */ "empty pattern input",
+            )
+        )
+    }
+
     /**
      * Either shows the bouncer or unlocks the device, if the bouncer doesn't need to be shown.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 5b1998d..f6794d4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -23,8 +23,7 @@
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import javax.inject.Inject
 import kotlin.math.ceil
 import kotlinx.coroutines.CoroutineScope
@@ -47,7 +46,7 @@
     @Application private val applicationScope: CoroutineScope,
     private val bouncerInteractor: BouncerInteractor,
     private val authenticationInteractor: AuthenticationInteractor,
-    featureFlags: FeatureFlags,
+    flags: SceneContainerFlags,
 ) {
     private val isInputEnabled: StateFlow<Boolean> =
         bouncerInteractor.isThrottled
@@ -102,7 +101,7 @@
             )
 
     init {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (flags.isEnabled()) {
             applicationScope.launch {
                 bouncerInteractor.isThrottled
                     .map { isThrottled ->
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index ca15f4e..80a41ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -34,6 +34,7 @@
     ) {
 
     private val _password = MutableStateFlow("")
+
     /** The password entered so far. */
     val password: StateFlow<String> = _password.asStateFlow()
 
@@ -48,6 +49,10 @@
             interactor.clearMessage()
         }
 
+        if (password.isNotEmpty()) {
+            interactor.onIntentionalUserInput()
+        }
+
         _password.value = password
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 4425f9f..85eaf0b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -46,10 +46,12 @@
 
     /** The number of columns in the dot grid. */
     val columnCount = 3
+
     /** The number of rows in the dot grid. */
     val rowCount = 3
 
     private val _selectedDots = MutableStateFlow<LinkedHashSet<PatternDotViewModel>>(linkedSetOf())
+
     /** The dots that were selected by the user, in the order of selection. */
     val selectedDots: StateFlow<List<PatternDotViewModel>> =
         _selectedDots
@@ -61,10 +63,12 @@
             )
 
     private val _currentDot = MutableStateFlow<PatternDotViewModel?>(null)
+
     /** The most-recently selected dot that the user selected. */
     val currentDot: StateFlow<PatternDotViewModel?> = _currentDot.asStateFlow()
 
     private val _dots = MutableStateFlow(defaultDots())
+
     /** All dots on the grid. */
     val dots: StateFlow<List<PatternDotViewModel>> = _dots.asStateFlow()
 
@@ -76,6 +80,11 @@
         interactor.resetMessage()
     }
 
+    /** Notifies that the user has placed down a pointer, not necessarily dragging just yet. */
+    fun onDown() {
+        interactor.onDown()
+    }
+
     /** Notifies that the user has started a drag gesture across the dot grid. */
     fun onDragStart() {
         interactor.clearMessage()
@@ -124,11 +133,13 @@
                             dot =
                                 PatternDotViewModel(
                                     x =
-                                        if (hitDot.x > dot.x) dot.x + 1
-                                        else if (hitDot.x < dot.x) dot.x - 1 else dot.x,
+                                        if (hitDot.x > dot.x) {
+                                            dot.x + 1
+                                        } else if (hitDot.x < dot.x) dot.x - 1 else dot.x,
                                     y =
-                                        if (hitDot.y > dot.y) dot.y + 1
-                                        else if (hitDot.y < dot.y) dot.y - 1 else dot.y,
+                                        if (hitDot.y > dot.y) {
+                                            dot.y + 1
+                                        } else if (hitDot.y < dot.y) dot.y - 1 else dot.y,
                                 )
                         }
                     }
@@ -148,6 +159,12 @@
     /** Notifies that the user has ended the drag gesture across the dot grid. */
     fun onDragEnd() {
         val pattern = _selectedDots.value.map { it.toCoordinate() }
+
+        if (pattern.size == 1) {
+            // Single dot patterns are treated as erroneous/false taps:
+            interactor.onFalseUserInput()
+        }
+
         _dots.value = defaultDots()
         _currentDot.value = null
         _selectedDots.value = linkedSetOf()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 844cf02..ebf939b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -88,6 +88,11 @@
         interactor.resetMessage()
     }
 
+    /** Notifies that the user has placed down a pointer. */
+    fun onDown() {
+        interactor.onDown()
+    }
+
     /** Notifies that the user clicked on a PIN button with the given digit value. */
     fun onPinButtonClicked(input: Int) {
         val pinInput = mutablePinInput.value
@@ -95,6 +100,8 @@
             interactor.clearMessage()
         }
 
+        interactor.onIntentionalUserInput()
+
         mutablePinInput.value = pinInput.append(input)
         tryAuthenticate(useAutoConfirm = true)
     }
@@ -148,8 +155,10 @@
 enum class ActionButtonAppearance {
     /** Button must not be shown. */
     Hidden,
+
     /** Button is shown, but with no background to make it less prominent. */
     Subtle,
+
     /** Button is shown. */
     Shown,
 }
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 4227a7a..b268095 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -29,12 +29,14 @@
 import android.view.WindowManager
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.ActivityIntentHelper
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import java.util.concurrent.Executor
 import javax.inject.Inject
@@ -43,10 +45,12 @@
  * Helps with handling camera-related gestures (for example, double-tap the power button to launch
  * the camera).
  */
+@SysUISingleton
 class CameraGestureHelper @Inject constructor(
     private val context: Context,
     private val centralSurfaces: CentralSurfaces,
     private val keyguardStateController: KeyguardStateController,
+    private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
     private val packageManager: PackageManager,
     private val activityManager: ActivityManager,
     private val activityStarter: ActivityStarter,
@@ -133,7 +137,7 @@
         centralSurfaces.startLaunchTransitionTimeout()
         // Call this to make sure the keyguard is ready to be dismissed once the next intent is
         // handled by the OS (in our case it is the activity we started right above)
-        centralSurfaces.readyForKeyguardDone()
+        statusBarKeyguardViewManager.readyForKeyguardDone()
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index 08e1e9a..f77f989 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -29,78 +29,21 @@
     void setShowingAod(boolean showingAod);
 
     /** */
-    void onNotificationStartDraggingDown();
-
-    /** */
-    void onNotificationStopDraggingDown();
-
-    /** */
-    void setNotificationExpanded();
-
-    /** */
-    void onQsDown();
-
-    /** */
     boolean shouldEnforceBouncer();
 
     /** */
-    void onTrackingStarted(boolean secure);
-
-    /** */
-    void onTrackingStopped();
-
-    /** */
-    void onLeftAffordanceOn();
-
-    /** */
-    void onCameraOn();
-
-    /** */
-    void onAffordanceSwipingStarted(boolean rightCorner);
-
-    /** */
-    void onAffordanceSwipingAborted();
-
-    /** */
-    void onStartExpandingFromPulse();
-
-    /** */
-    void onExpansionFromPulseStopped();
-
-    /** */
     void onScreenOnFromTouch();
 
     /** */
     boolean isReportingEnabled();
 
     /** */
-    void onUnlockHintStarted();
-
-    /** */
-    void onCameraHintStarted();
-
-    /** */
-    void onLeftAffordanceHintStarted();
-
-    /** */
     void onScreenTurningOn();
 
     /** */
     void onScreenOff();
 
     /** */
-    void onNotificationStopDismissing();
-
-    /** */
-    void onNotificationDismissed();
-
-    /** */
-    void onNotificationStartDismissing();
-
-    /** */
-    void onNotificationDoubleTap(boolean accepted, float dx, float dy);
-
-    /** */
     void onBouncerShown();
 
     /** */
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorActual.kt
similarity index 70%
copy from tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
copy to packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorActual.kt
index fe91260..3eaad1f 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorActual.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.apkverity.feature_x;
+package com.android.systemui.classifier
 
-import android.app.Activity;
+import javax.inject.Qualifier
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class FalsingCollectorActual
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index f335d1d..c0ee71c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -29,59 +29,11 @@
     }
 
     @Override
-    public void onNotificationStartDraggingDown() {
-    }
-
-    @Override
-    public void onNotificationStopDraggingDown() {
-    }
-
-    @Override
-    public void setNotificationExpanded() {
-    }
-
-    @Override
-    public void onQsDown() {
-    }
-
-    @Override
     public boolean shouldEnforceBouncer() {
         return false;
     }
 
     @Override
-    public void onTrackingStarted(boolean secure) {
-    }
-
-    @Override
-    public void onTrackingStopped() {
-    }
-
-    @Override
-    public void onLeftAffordanceOn() {
-    }
-
-    @Override
-    public void onCameraOn() {
-    }
-
-    @Override
-    public void onAffordanceSwipingStarted(boolean rightCorner) {
-    }
-
-    @Override
-    public void onAffordanceSwipingAborted() {
-    }
-
-    @Override
-    public void onStartExpandingFromPulse() {
-    }
-
-    @Override
-    public void onExpansionFromPulseStopped() {
-    }
-
-    @Override
     public void onScreenOnFromTouch() {
     }
 
@@ -91,18 +43,6 @@
     }
 
     @Override
-    public void onUnlockHintStarted() {
-    }
-
-    @Override
-    public void onCameraHintStarted() {
-    }
-
-    @Override
-    public void onLeftAffordanceHintStarted() {
-    }
-
-    @Override
     public void onScreenTurningOn() {
     }
 
@@ -111,22 +51,6 @@
     }
 
     @Override
-    public void onNotificationStopDismissing() {
-    }
-
-    @Override
-    public void onNotificationDismissed() {
-    }
-
-    @Override
-    public void onNotificationStartDismissing() {
-    }
-
-    @Override
-    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
-    }
-
-    @Override
     public void onBouncerShown() {
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 6a021f6..39c01f7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -103,10 +103,6 @@
 
     private final BatteryStateChangeCallback mBatteryListener = new BatteryStateChangeCallback() {
         @Override
-        public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        }
-
-        @Override
         public void onWirelessChargingChanged(boolean isWirelessCharging) {
             if (isWirelessCharging || mDockManager.isDocked()) {
                 mProximitySensor.pause();
@@ -169,34 +165,21 @@
 
     @Override
     public void onSuccessfulUnlock() {
+        logDebug("REAL: onSuccessfulUnlock");
         mFalsingManager.onSuccessfulUnlock();
         sessionEnd();
     }
 
     @Override
     public void setShowingAod(boolean showingAod) {
+        logDebug("REAL: setShowingAod(" + showingAod + ")");
         mShowingAod = showingAod;
         updateSessionActive();
     }
 
-    @Override
-    public void onNotificationStartDraggingDown() {
-    }
-
-    @Override
-    public void onNotificationStopDraggingDown() {
-    }
-
-    @Override
-    public void setNotificationExpanded() {
-    }
-
-    @Override
-    public void onQsDown() {
-    }
-
     @VisibleForTesting
     void onQsExpansionChanged(Boolean expanded) {
+        logDebug("REAL: onQsExpansionChanged(" + expanded + ")");
         if (expanded) {
             unregisterSensors();
         } else if (mSessionStarted) {
@@ -210,39 +193,8 @@
     }
 
     @Override
-    public void onTrackingStarted(boolean secure) {
-    }
-
-    @Override
-    public void onTrackingStopped() {
-    }
-
-    @Override
-    public void onLeftAffordanceOn() {
-    }
-
-    @Override
-    public void onCameraOn() {
-    }
-
-    @Override
-    public void onAffordanceSwipingStarted(boolean rightCorner) {
-    }
-
-    @Override
-    public void onAffordanceSwipingAborted() {
-    }
-
-    @Override
-    public void onStartExpandingFromPulse() {
-    }
-
-    @Override
-    public void onExpansionFromPulseStopped() {
-    }
-
-    @Override
     public void onScreenOnFromTouch() {
+        logDebug("REAL: onScreenOnFromTouch");
         onScreenTurningOn();
     }
 
@@ -252,52 +204,28 @@
     }
 
     @Override
-    public void onUnlockHintStarted() {
-    }
-
-    @Override
-    public void onCameraHintStarted() {
-    }
-
-    @Override
-    public void onLeftAffordanceHintStarted() {
-    }
-
-    @Override
     public void onScreenTurningOn() {
+        logDebug("REAL: onScreenTurningOn");
         mScreenOn = true;
         updateSessionActive();
     }
 
     @Override
     public void onScreenOff() {
+        logDebug("REAL: onScreenOff");
         mScreenOn = false;
         updateSessionActive();
     }
 
     @Override
-    public void onNotificationStopDismissing() {
-    }
-
-    @Override
-    public void onNotificationDismissed() {
-    }
-
-    @Override
-    public void onNotificationStartDismissing() {
-    }
-
-    @Override
-    public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
-    }
-
-    @Override
     public void onBouncerShown() {
+        logDebug("REAL: onBouncerShown");
         unregisterSensors();
     }
 
     @Override
     public void onBouncerHidden() {
+        logDebug("REAL: onBouncerHidden");
         if (mSessionStarted) {
             registerSensors();
         }
@@ -305,6 +233,7 @@
 
     @Override
     public void onTouchEvent(MotionEvent ev) {
+        logDebug("REAL: onTouchEvent(" + ev.getActionMasked() + ")");
         if (!mKeyguardStateController.isShowing()) {
             avoidGesture();
             return;
@@ -334,6 +263,7 @@
 
     @Override
     public void onMotionEventComplete() {
+        logDebug("REAL: onMotionEventComplete");
         // We must delay processing the completion because of the way Android handles click events.
         // It generally delays executing them immediately, instead choosing to give the UI a chance
         // to respond to touch events before acknowledging the click. As such, we must also delay,
@@ -350,6 +280,7 @@
 
     @Override
     public void avoidGesture() {
+        logDebug("REAL: avoidGesture");
         mAvoidGesture = true;
         if (mPendingDownEvent != null) {
             mPendingDownEvent.recycle();
@@ -359,6 +290,7 @@
 
     @Override
     public void cleanup() {
+        logDebug("REAL: cleanup");
         unregisterSensors();
         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
         mStatusBarStateController.removeCallback(mStatusBarStateListener);
@@ -368,11 +300,13 @@
 
     @Override
     public void updateFalseConfidence(FalsingClassifier.Result result) {
+        logDebug("REAL: updateFalseConfidence(" + result.isFalse() + ")");
         mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis());
     }
 
     @Override
     public void onA11yAction() {
+        logDebug("REAL: onA11yAction");
         if (mPendingDownEvent != null) {
             mPendingDownEvent.recycle();
             mPendingDownEvent = null;
@@ -427,17 +361,13 @@
 
 
     static void logDebug(String msg) {
-        logDebug(msg, null);
-    }
-
-    static void logDebug(String msg, Throwable throwable) {
         if (DEBUG) {
-            Log.d(TAG, msg, throwable);
+            logDebug(msg);
         }
     }
 
     private static class ProximityEventImpl implements FalsingManager.ProximityEvent {
-        private ThresholdSensorEvent mThresholdSensorEvent;
+        private final ThresholdSensorEvent mThresholdSensorEvent;
 
         ProximityEventImpl(ThresholdSensorEvent thresholdSensorEvent) {
             mThresholdSensorEvent = thresholdSensorEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt
new file mode 100644
index 0000000..e5b404f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorNoOp.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier
+
+import android.view.MotionEvent
+import com.android.systemui.classifier.FalsingCollectorImpl.logDebug
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+@SysUISingleton
+class FalsingCollectorNoOp @Inject constructor() : FalsingCollector {
+    override fun onSuccessfulUnlock() {
+        logDebug("NOOP: onSuccessfulUnlock")
+    }
+
+    override fun setShowingAod(showingAod: Boolean) {
+        logDebug("NOOP: setShowingAod($showingAod)")
+    }
+
+    override fun shouldEnforceBouncer(): Boolean = false
+
+    override fun onScreenOnFromTouch() {
+        logDebug("NOOP: onScreenOnFromTouch")
+    }
+
+    override fun isReportingEnabled(): Boolean = false
+
+    override fun onScreenTurningOn() {
+        logDebug("NOOP: onScreenTurningOn")
+    }
+
+    override fun onScreenOff() {
+        logDebug("NOOP: onScreenOff")
+    }
+
+    override fun onBouncerShown() {
+        logDebug("NOOP: onBouncerShown")
+    }
+
+    override fun onBouncerHidden() {
+        logDebug("NOOP: onBouncerHidden")
+    }
+
+    override fun onTouchEvent(ev: MotionEvent) {
+        logDebug("NOOP: onTouchEvent(${ev.actionMasked})")
+    }
+
+    override fun onMotionEventComplete() {
+        logDebug("NOOP: onMotionEventComplete")
+    }
+
+    override fun avoidGesture() {
+        logDebug("NOOP: avoidGesture")
+    }
+
+    override fun cleanup() {
+        logDebug("NOOP: cleanup")
+    }
+
+    override fun updateFalseConfidence(result: FalsingClassifier.Result) {
+        logDebug("NOOP: updateFalseConfidence(${result.isFalse})")
+    }
+
+    override fun onA11yAction() {
+        logDebug("NOOP: onA11yAction")
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
index c7f3b2d..0a1aed6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingModule.java
@@ -22,19 +22,20 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.statusbar.phone.NotificationTapHelper;
 
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 
 import javax.inject.Named;
 
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.ElementsIntoSet;
-
 /** Dagger Module for Falsing. */
 @Module
 public interface FalsingModule {
@@ -45,10 +46,20 @@
     String DOUBLE_TAP_TIMEOUT_MS = "falsing_double_tap_timeout_ms";
     String IS_FOLDABLE_DEVICE = "falsing_foldable_device";
 
-    /** */
-    @Binds
+    /** Provides the actual {@link FalsingCollector} if the scene container feature is off. */
+    @Provides
     @SysUISingleton
-    FalsingCollector bindsFalsingCollector(FalsingCollectorImpl impl);
+    static FalsingCollector providesFalsingCollectorLegacy(
+            FalsingCollectorImpl impl,
+            FalsingCollectorNoOp noOp,
+            SceneContainerFlags flags) {
+        return flags.isEnabled() ? noOp : impl;
+    }
+
+    /** Provides the actual {@link FalsingCollector}. */
+    @Binds
+    @FalsingCollectorActual
+    FalsingCollector bindsFalsingCollectorActual(FalsingCollectorImpl impl);
 
     /** */
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
new file mode 100644
index 0000000..2e861c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/domain/interactor/FalsingInteractor.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier.domain.interactor
+
+import android.view.MotionEvent
+import com.android.systemui.classifier.FalsingClassifier
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorActual
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * Exposes the subset of the [FalsingCollector] API that's required by external callers.
+ *
+ * E.g. methods of [FalsingCollector] that are not exposed by this class don't need to be invoked by
+ * external callers as they're already called by the scene framework.
+ */
+@SysUISingleton
+class FalsingInteractor
+@Inject
+constructor(
+    @FalsingCollectorActual private val collector: FalsingCollector,
+) {
+    /**
+     * Notifies of a [MotionEvent] that passed through the UI.
+     *
+     * Must call [onMotionEventComplete] when done with this event.
+     */
+    fun onTouchEvent(event: MotionEvent) = collector.onTouchEvent(event)
+
+    /**
+     * Notifies that a [MotionEvent] has finished being dispatched through the UI.
+     *
+     * Must be called after each call to [onTouchEvent].
+     */
+    fun onMotionEventComplete() = collector.onMotionEventComplete()
+
+    /**
+     * Instructs the falsing system to ignore the rest of the current input gesture; automatically
+     * resets when another gesture is started (with the next down event).
+     */
+    fun avoidGesture() = collector.avoidGesture()
+
+    /**
+     * Inserts the given [result] into the falsing system, affecting future runs of the classifier
+     * as if this was a result that had organically happened before.
+     */
+    fun updateFalseConfidence(
+        result: FalsingClassifier.Result,
+    ) = collector.updateFalseConfidence(result)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt
index c3369da..3ff1f09 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprint.kt
@@ -16,10 +16,10 @@
 
 package com.android.systemui.communal.ui.view.layout.blueprints
 
-import androidx.constraintlayout.widget.ConstraintSet
 import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.repository.KeyguardBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardSection
 import javax.inject.Inject
 
 /** Blueprint for communal mode. */
@@ -28,13 +28,10 @@
 class DefaultCommunalBlueprint
 @Inject
 constructor(
-    private val defaultCommunalWidgetSection: DefaultCommunalWidgetSection,
+    defaultCommunalWidgetSection: DefaultCommunalWidgetSection,
 ) : KeyguardBlueprint {
     override val id: String = COMMUNAL
-
-    override fun apply(constraintSet: ConstraintSet) {
-        defaultCommunalWidgetSection.apply(constraintSet)
-    }
+    override val sections: Set<KeyguardSection> = setOf(defaultCommunalWidgetSection)
 
     companion object {
         const val COMMUNAL = "communal"
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalWidgetSection.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalWidgetSection.kt
index b0e3132..8640c97 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalWidgetSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/view/layout/sections/DefaultCommunalWidgetSection.kt
@@ -17,18 +17,50 @@
 package com.android.systemui.communal.ui.view.layout.sections
 
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.communal.ui.adapter.CommunalWidgetViewAdapter
+import com.android.systemui.communal.ui.binder.CommunalWidgetViewBinder
+import com.android.systemui.communal.ui.viewmodel.CommunalWidgetViewModel
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import dagger.Lazy
 import javax.inject.Inject
 
-class DefaultCommunalWidgetSection @Inject constructor() : KeyguardSection {
+class DefaultCommunalWidgetSection
+@Inject
+constructor(
+    private val featureFlags: FeatureFlags,
+    private val keyguardRootView: KeyguardRootView,
+    private val communalWidgetViewModel: CommunalWidgetViewModel,
+    private val communalWidgetViewAdapter: CommunalWidgetViewAdapter,
+    private val keyguardBlueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
+) : KeyguardSection() {
     private val widgetAreaViewId = R.id.communal_widget_wrapper
 
-    override fun apply(constraintSet: ConstraintSet) {
+    override fun addViews(constraintLayout: ConstraintLayout) {}
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (!featureFlags.isEnabled(Flags.WIDGET_ON_KEYGUARD)) {
+            return
+        }
+
+        CommunalWidgetViewBinder.bind(
+            keyguardRootView,
+            communalWidgetViewModel,
+            communalWidgetViewAdapter,
+            keyguardBlueprintInteractor.get(),
+        )
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         constraintSet.apply {
             constrainWidth(widgetAreaViewId, WRAP_CONTENT)
             constrainHeight(widgetAreaViewId, WRAP_CONTENT)
@@ -36,4 +68,6 @@
             connect(widgetAreaViewId, END, PARENT_ID, END)
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
index d3174f1..adb0bf3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
@@ -71,14 +71,9 @@
     private var resolved: Boolean = false
 
     @WorkerThread
-    fun resolvePanelActivity(
-        allowAllApps: Boolean = false
-    ) {
+    fun resolvePanelActivity() {
         if (resolved) return
         resolved = true
-        val validPackages = context.resources
-            .getStringArray(R.array.config_controlsPreferredPackages)
-        if (componentName.packageName !in validPackages && !allowAllApps) return
         panelActivity = _panelActivity?.let {
             val resolveInfos = mPm.queryIntentActivitiesAsUser(
                 Intent().setComponent(it),
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
index 94e5633..88b9612 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.controls.dagger
 
-import android.content.Context
 import com.android.internal.widget.LockPatternUtils
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
 import com.android.systemui.controls.controller.ControlsController
@@ -44,10 +43,9 @@
 @Inject
 constructor(
     @ControlsFeatureEnabled private val featureEnabled: Boolean,
-    private val context: Context,
-    private val lazyControlsController: Lazy<ControlsController>,
-    private val lazyControlsUiController: Lazy<ControlsUiController>,
-    private val lazyControlsListingController: Lazy<ControlsListingController>,
+    lazyControlsController: Lazy<ControlsController>,
+    lazyControlsUiController: Lazy<ControlsUiController>,
+    lazyControlsListingController: Lazy<ControlsListingController>,
     private val lockPatternUtils: LockPatternUtils,
     private val keyguardStateController: KeyguardStateController,
     private val userTracker: UserTracker,
@@ -55,27 +53,25 @@
     optionalControlsTileResourceConfiguration: Optional<ControlsTileResourceConfiguration>
 ) {
 
+    private val controlsController: Optional<ControlsController> =
+        optionalIf(isEnabled(), lazyControlsController)
+    private val controlsUiController: Optional<ControlsUiController> =
+        optionalIf(isEnabled(), lazyControlsUiController)
+    private val controlsListingController: Optional<ControlsListingController> =
+        optionalIf(isEnabled(), lazyControlsListingController)
+
     val canShowWhileLockedSetting: StateFlow<Boolean> =
         controlsSettingsRepository.canShowControlsInLockscreen
 
     private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration =
         optionalControlsTileResourceConfiguration.orElse(ControlsTileResourceConfigurationImpl())
 
-    fun getControlsController(): Optional<ControlsController> {
-        return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
-    }
+    fun getControlsController(): Optional<ControlsController> = controlsController
 
-    fun getControlsUiController(): Optional<ControlsUiController> {
-        return if (featureEnabled) Optional.of(lazyControlsUiController.get()) else Optional.empty()
-    }
+    fun getControlsUiController(): Optional<ControlsUiController> = controlsUiController
 
-    fun getControlsListingController(): Optional<ControlsListingController> {
-        return if (featureEnabled) {
-            Optional.of(lazyControlsListingController.get())
-        } else {
-            Optional.empty()
-        }
-    }
+    fun getControlsListingController(): Optional<ControlsListingController> =
+        controlsListingController
 
     /** @return true if controls are feature-enabled and the user has the setting enabled */
     fun isEnabled() = featureEnabled
@@ -118,4 +114,11 @@
     fun getTileImageId(): Int {
         return controlsTileResourceConfiguration.getTileImageId()
     }
+
+    private fun <T : Any> optionalIf(condition: Boolean, provider: Lazy<T>): Optional<T> =
+        if (condition) {
+            Optional.of(provider.get())
+        } else {
+            Optional.empty()
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 83bec66..74e1dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -33,7 +33,6 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.ActivityTaskManagerProxy
 import com.android.systemui.util.asIndenting
@@ -125,9 +124,8 @@
 
     private fun updateServices(newServices: List<ControlsServiceInfo>) {
         if (activityTaskManagerProxy.supportsMultiWindow(context)) {
-            val allowAllApps = featureFlags.isEnabled(Flags.APP_PANELS_ALL_APPS_ALLOWED)
             newServices.forEach {
-                it.resolvePanelActivity(allowAllApps) }
+                it.resolvePanelActivity() }
         }
 
         if (newServices != availableServices) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
index 0b57e79..d011dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
@@ -22,6 +22,7 @@
 import android.graphics.drawable.LayerDrawable
 import android.view.View
 import android.service.controls.Control
+import android.service.controls.templates.TemperatureControlTemplate
 import android.service.controls.templates.ThumbnailTemplate
 import android.util.TypedValue
 
@@ -68,7 +69,9 @@
     override fun bind(cws: ControlWithState, colorOffset: Int) {
         this.control = cws.control!!
         cvh.setStatusText(control.getStatusText())
-        template = control.getControlTemplate() as ThumbnailTemplate
+        template = control.controlTemplate as? ThumbnailTemplate
+                ?: (control.controlTemplate as TemperatureControlTemplate).template
+                        as ThumbnailTemplate
 
         val ld = cvh.layout.getBackground() as LayerDrawable
         val clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 3562477..7b58b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -40,6 +40,7 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsImplementation;
 import com.android.systemui.rotationlock.RotationLockModule;
+import com.android.systemui.scene.SceneContainerFrameworkModule;
 import com.android.systemui.screenshot.ReferenceScreenshotModule;
 import com.android.systemui.settings.dagger.MultiUserUtilsModule;
 import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
@@ -57,6 +58,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.AospPolicyModule;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -95,6 +97,7 @@
 @Module(includes = {
         AospPolicyModule.class,
         BatterySaverModule.class,
+        CollapsedStatusBarFragmentStartableModule.class,
         GestureModule.class,
         MediaModule.class,
         MultiUserUtilsModule.class,
@@ -102,6 +105,7 @@
         QSModule.class,
         ReferenceScreenshotModule.class,
         RotationLockModule.class,
+        SceneContainerFrameworkModule.class,
         StatusBarEventsModule.class,
         StartCentralSurfacesModule.class,
         VolumeModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 6fdb4ca..dcacd09 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,6 +22,7 @@
 import com.android.systemui.InitController;
 import com.android.systemui.SystemUIAppComponentFactoryBase;
 import com.android.systemui.dagger.qualifiers.PerUser;
+import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardSliceProvider;
 import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
@@ -140,6 +141,7 @@
         getMediaMuteAwaitConnectionCli();
         getNearbyMediaDevicesManager();
         getUnfoldLatencyTracker().init();
+        getConnectingDisplayViewModel().init();
         getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init);
         getFoldStateLogger().ifPresent(FoldStateLogger::init);
         getUnfoldTransitionProgressProvider().ifPresent((progressProvider) ->
@@ -229,6 +231,11 @@
     NearbyMediaDevicesManager getNearbyMediaDevicesManager();
 
     /**
+     * Creates a ConnectingDisplayViewModel
+     */
+    ConnectingDisplayViewModel getConnectingDisplayViewModel();
+
+    /**
      * Returns {@link CoreStartable}s that should be started with the application.
      */
     Map<Class<?>, Provider<CoreStartable>> getStartables();
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 1b2a9eb..7ce7ce94 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SliceBroadcastRelayHandler
 import com.android.systemui.accessibility.SystemActions
 import com.android.systemui.accessibility.WindowMagnification
+import com.android.systemui.back.domain.interactor.BackActionInteractor
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.biometrics.BiometricNotificationService
 import com.android.systemui.clipboardoverlay.ClipboardListener
@@ -346,4 +347,9 @@
     abstract fun bindStatusBarHeadsUpChangeListener(
         impl: StatusBarHeadsUpChangeListener
     ): CoreStartable
+
+    @Binds
+    @IntoMap
+    @ClassKey(BackActionInteractor::class)
+    abstract fun bindBackActionInteractor(impl: BackActionInteractor): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index ade7684..7ee0ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -76,7 +76,6 @@
 import com.android.systemui.qs.footer.dagger.FooterActionsModule;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.retail.dagger.RetailModeModule;
-import com.android.systemui.scene.SceneContainerFrameworkModule;
 import com.android.systemui.scene.ui.view.WindowRootViewComponent;
 import com.android.systemui.screenrecord.ScreenRecordModule;
 import com.android.systemui.screenshot.dagger.ScreenshotModule;
@@ -109,7 +108,6 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LetterboxModule;
 import com.android.systemui.statusbar.phone.NotificationIconAreaControllerModule;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
 import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -126,7 +124,6 @@
 import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
 import com.android.systemui.util.dagger.UtilModule;
 import com.android.systemui.util.kotlin.CoroutinesModule;
-import com.android.systemui.util.leak.GarbageMonitorModule;
 import com.android.systemui.util.sensors.SensorModule;
 import com.android.systemui.util.settings.SettingsUtilModule;
 import com.android.systemui.util.time.SystemClock;
@@ -179,7 +176,6 @@
             FlagsModule.class,
             SystemPropertiesFlagsModule.class,
             FooterActionsModule.class,
-            GarbageMonitorModule.class,
             KeyboardModule.class,
             LetterboxModule.class,
             KeyguardBlueprintModule.class,
@@ -196,7 +192,6 @@
             QRCodeScannerModule.class,
             QSFragmentStartableModule.class,
             RetailModeModule.class,
-            SceneContainerFrameworkModule.class,
             ScreenshotModule.class,
             SensorModule.class,
             SecurityRepositoryModule.class,
@@ -219,7 +214,6 @@
             WalletModule.class
         },
         subcomponents = {
-            CentralSurfacesComponent.class,
             ComplicationComponent.class,
             NavigationBarComponent.class,
             NotificationRowComponent.class,
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 b18f7bf..82b0324 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
@@ -22,25 +22,59 @@
 import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
 import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
 import android.os.Handler
+import android.os.Trace
+import android.util.Log
 import android.view.Display
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.Compile
 import com.android.systemui.util.traceSection
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 
 /** Provides a [Flow] of [Display] as returned by [DisplayManager]. */
 interface DisplayRepository {
     /** Provides a nullable set of displays. */
     val displays: Flow<Set<Display>>
+
+    /**
+     * Pending display id that can be enabled/disabled.
+     *
+     * When `null`, it means there is no pending display waiting to be enabled.
+     */
+    val pendingDisplay: Flow<PendingDisplay?>
+
+    /** Represents a connected display that has not been enabled yet. */
+    interface PendingDisplay {
+        /** Id of the pending display. */
+        val id: Int
+
+        /** Enables the display, making it available to the system. */
+        suspend fun enable()
+
+        /**
+         * Ignores the pending display. When called, this specific display id doesn't appear as
+         * pending anymore until the display is disconnected and reconnected again.
+         */
+        suspend fun ignore()
+
+        /** Disables the display, making it unavailable to the system. */
+        suspend fun disable()
+    }
 }
 
 @SysUISingleton
@@ -53,7 +87,8 @@
     @Background backgroundCoroutineDispatcher: CoroutineDispatcher
 ) : DisplayRepository {
 
-    override val displays: Flow<Set<Display>> =
+    // Displays are enabled only after receiving them in [onDisplayAdded]
+    private val enabledDisplays: StateFlow<Set<Display>> =
         conflatedCallbackFlow {
                 val callback =
                     object : DisplayListener {
@@ -85,8 +120,136 @@
                 initialValue = getDisplays()
             )
 
-    fun getDisplays(): Set<Display> =
+    private fun getDisplays(): Set<Display> =
         traceSection("DisplayRepository#getDisplays()") {
             displayManager.displays?.toSet() ?: emptySet()
         }
+
+    /** Propagate to the listeners only enabled displays */
+    override val displays: Flow<Set<Display>> = enabledDisplays
+
+    private val enabledDisplayIds: Flow<Set<Int>> =
+        enabledDisplays
+            .map { enabledDisplaysSet -> enabledDisplaysSet.map { it.displayId }.toSet() }
+            .debugLog("enabledDisplayIds")
+
+    private val ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
+
+    /* keeps connected displays until they are disconnected. */
+    private val connectedDisplayIds: StateFlow<Set<Int>> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : DisplayConnectionListener {
+                        private val connectedIds = mutableSetOf<Int>()
+                        override fun onDisplayConnected(id: Int) {
+                            if (DEBUG) {
+                                Log.d(TAG, "$id connected")
+                            }
+                            connectedIds += id
+                            ignoredDisplayIds.value -= id
+                            trySend(connectedIds.toSet())
+                        }
+
+                        override fun onDisplayDisconnected(id: Int) {
+                            connectedIds -= id
+                            if (DEBUG) {
+                                Log.d(TAG, "$id disconnected. Connected ids: $connectedIds")
+                            }
+                            ignoredDisplayIds.value -= id
+                            trySend(connectedIds.toSet())
+                        }
+                    }
+                displayManager.registerDisplayListener(
+                    callback,
+                    backgroundHandler,
+                    DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+                )
+                awaitClose { displayManager.unregisterDisplayListener(callback) }
+            }
+            .distinctUntilChanged()
+            .debugLog("connectedDisplayIds")
+            .flowOn(backgroundCoroutineDispatcher)
+            .stateIn(
+                applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = emptySet()
+            )
+
+    /**
+     * Pending displays are the ones connected, but not enabled and not ignored. A connected display
+     * is ignored after the user makes the decision to use it or not. For now, the initial decision
+     * from the user is final and not reversible.
+     */
+    private val pendingDisplayIds: Flow<Set<Int>> =
+        combine(enabledDisplayIds, connectedDisplayIds, ignoredDisplayIds) {
+                enabledDisplaysIds,
+                connectedDisplayIds,
+                ignoredDisplayIds ->
+                if (DEBUG) {
+                    Log.d(
+                        TAG,
+                        "combining enabled: $enabledDisplaysIds, " +
+                            "connected: $connectedDisplayIds, ignored: $ignoredDisplayIds"
+                    )
+                }
+                connectedDisplayIds - enabledDisplaysIds - ignoredDisplayIds
+            }
+            .debugLog("pendingDisplayIds")
+
+    override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?> =
+        pendingDisplayIds
+            .map { pendingDisplayIds ->
+                val id = pendingDisplayIds.maxOrNull() ?: return@map null
+                object : DisplayRepository.PendingDisplay {
+                    override val id = id
+                    override suspend fun enable() {
+                        traceSection("DisplayRepository#enable($id)") {
+                            displayManager.enableConnectedDisplay(id)
+                        }
+                        // After the display has been enabled, it is automatically ignored.
+                        ignore()
+                    }
+
+                    override suspend fun ignore() {
+                        traceSection("DisplayRepository#ignore($id)") {
+                            ignoredDisplayIds.value += id
+                        }
+                    }
+
+                    override suspend fun disable() {
+                        ignore()
+                        traceSection("DisplayRepository#disable($id)") {
+                            displayManager.disableConnectedDisplay(id)
+                        }
+                    }
+                }
+            }
+            .debugLog("pendingDisplay")
+
+    private fun <T> Flow<T>.debugLog(flowName: String): Flow<T> {
+        return if (DEBUG) {
+            this.onEach {
+                Log.d(TAG, "$flowName: $it")
+                Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_APP, "$TAG#$flowName", 0)
+                Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, "$TAG#$flowName", "$it", 0)
+            }
+        } else {
+            this
+        }
+    }
+
+    private companion object {
+        const val TAG = "DisplayRepository"
+        val DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Compile.IS_DEBUG
+    }
+}
+
+/** Used to provide default implementations for all methods. */
+private interface DisplayConnectionListener : DisplayListener {
+
+    override fun onDisplayConnected(id: Int) {}
+    override fun onDisplayDisconnected(id: Int) {}
+    override fun onDisplayAdded(id: Int) {}
+    override fun onDisplayRemoved(id: Int) {}
+    override fun onDisplayChanged(id: Int) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
index 4b957c7..11ed96d 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractor.kt
@@ -19,9 +19,12 @@
 import android.view.Display
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 
@@ -37,18 +40,36 @@
      */
     val connectedDisplayState: Flow<State>
 
+    /** Pending display that can be enabled to be used by the system. */
+    val pendingDisplay: Flow<PendingDisplay?>
+
     /** Possible connected display state. */
     enum class State {
         DISCONNECTED,
         CONNECTED,
         CONNECTED_SECURE,
     }
+
+    /** Represents a connected display that has not been enabled yet for the UI layer. */
+    interface PendingDisplay {
+        /** Enables the display, making it available to the system. */
+        suspend fun enable()
+
+        /**
+         * Ignores the pending display.
+         *
+         * When called, this specific display id doesn't appear as pending anymore until the display
+         * is disconnected and reconnected again.
+         */
+        suspend fun ignore()
+    }
 }
 
 @SysUISingleton
 class ConnectedDisplayInteractorImpl
 @Inject
 constructor(
+    keyguardRepository: KeyguardRepository,
     displayRepository: DisplayRepository,
 ) : ConnectedDisplayInteractor {
 
@@ -70,4 +91,22 @@
                 }
             }
             .distinctUntilChanged()
+
+    // Provides the pending display only if the lockscreen is unlocked
+    override val pendingDisplay: Flow<PendingDisplay?> =
+        displayRepository.pendingDisplay.combine(keyguardRepository.isKeyguardShowing) {
+            repositoryPendingDisplay,
+            keyguardShowing ->
+            if (repositoryPendingDisplay != null && !keyguardShowing) {
+                repositoryPendingDisplay.toInteractorPendingDisplay()
+            } else {
+                null
+            }
+        }
+
+    private fun DisplayRepository.PendingDisplay.toInteractorPendingDisplay(): PendingDisplay =
+        object : PendingDisplay {
+            override suspend fun enable() = this@toInteractorPendingDisplay.enable()
+            override suspend fun ignore() = this@toInteractorPendingDisplay.ignore()
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
new file mode 100644
index 0000000..ecc9d0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/view/MirroringConfirmationDialog.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.display.ui.view
+
+import android.app.Dialog
+import android.content.Context
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.view.WindowManager
+import android.widget.TextView
+import com.android.systemui.R
+
+/**
+ * Dialog used to decide what to do with a connected display.
+ *
+ * [onCancelMirroring] is called **only** if mirroring didn't start, or when the dismiss button is
+ * pressed.
+ */
+class MirroringConfirmationDialog(
+    context: Context,
+    private val onStartMirroringClickListener: View.OnClickListener,
+    private val onCancelMirroring: View.OnClickListener,
+) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
+
+    private lateinit var mirrorButton: TextView
+    private lateinit var dismissButton: TextView
+    private var enabledPressed = false
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        window?.apply {
+            setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+            addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
+            setGravity(Gravity.BOTTOM)
+        }
+        setContentView(R.layout.connected_display_dialog)
+        setCanceledOnTouchOutside(true)
+        mirrorButton =
+            requireViewById<TextView>(R.id.enable_display).apply {
+                setOnClickListener(onStartMirroringClickListener)
+                enabledPressed = true
+            }
+        dismissButton =
+            requireViewById<TextView>(R.id.cancel).apply { setOnClickListener(onCancelMirroring) }
+
+        setOnDismissListener {
+            if (!enabledPressed) {
+                onCancelMirroring.onClick(null)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
new file mode 100644
index 0000000..86ef439
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/ui/viewmodel/ConnectingDisplayViewModel.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.display.ui.viewmodel
+
+import android.app.Dialog
+import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
+import com.android.systemui.display.ui.view.MirroringConfirmationDialog
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+
+/**
+ * Shows/hides a dialog to allow the user to decide whether to use the external display for
+ * mirroring.
+ */
+@SysUISingleton
+class ConnectingDisplayViewModel
+@Inject
+constructor(
+    private val context: Context,
+    private val connectedDisplayInteractor: ConnectedDisplayInteractor,
+    @Application private val scope: CoroutineScope,
+    @Background private val bgDispatcher: CoroutineDispatcher
+) {
+
+    private var dialog: Dialog? = null
+
+    /** Starts listening for pending displays. */
+    fun init() {
+        connectedDisplayInteractor.pendingDisplay
+            .onEach { pendingDisplay ->
+                if (pendingDisplay == null) {
+                    hideDialog()
+                } else {
+                    showDialog(pendingDisplay)
+                }
+            }
+            .launchIn(scope)
+    }
+
+    private fun showDialog(pendingDisplay: PendingDisplay) {
+        hideDialog()
+        dialog =
+            MirroringConfirmationDialog(
+                    context,
+                    onStartMirroringClickListener = {
+                        scope.launch(bgDispatcher) { pendingDisplay.enable() }
+                        hideDialog()
+                    },
+                    onCancelMirroring = {
+                        scope.launch(bgDispatcher) { pendingDisplay.ignore() }
+                        hideDialog()
+                    }
+                )
+                .apply { show() }
+    }
+
+    private fun hideDialog() {
+        dialog?.hide()
+        dialog = null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index e9a539f..59e30a1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -39,6 +39,14 @@
     @JvmField val TEAMFOOD = unreleasedFlag("teamfood")
 
     // 100 - notification
+    // TODO(b/297792660): Tracking Bug
+    val ADD_TRANSIENT_HUN_IN_STACK_STATE_ANIMATOR =
+        unreleasedFlag("add_transient_hun_in_stack_state_animator", teamfood = false)
+
+    // TODO(b/298308067): Tracking Bug
+    val SWIPE_UNCLEARED_TRANSIENT_VIEW_FIX =
+        unreleasedFlag("swipe_uncleared_transient_view_fix", teamfood = false)
+
     // TODO(b/254512751): Tracking Bug
     val NOTIFICATION_PIPELINE_DEVELOPER_LOGGING =
         unreleasedFlag("notification_pipeline_developer_logging")
@@ -107,7 +115,7 @@
     val BUILDER_EXTRAS_OVERRIDE =
         sysPropBooleanFlag(
             "persist.sysui.notification.builder_extras_override",
-            default = true
+            default = false
         )
 
     /** Only notify group expansion listeners when a change happens. */
@@ -204,6 +212,11 @@
     @JvmField
     val LOCK_SCREEN_LONG_PRESS_ENABLED = releasedFlag("lock_screen_long_press_enabled")
 
+    /** Inflate and bind views upon emitting a blueprint value . */
+    // TODO(b/297365780): Tracking Bug
+    @JvmField
+    val LAZY_INFLATE_KEYGUARD = releasedFlag("lazy_inflate_keyguard")
+
     /** Enables UI updates for AI wallpapers in the wallpaper picker. */
     // TODO(b/267722622): Tracking Bug
     @JvmField val WALLPAPER_PICKER_UI_FOR_AIWP = releasedFlag("wallpaper_picker_ui_for_aiwp")
@@ -370,6 +383,9 @@
 
     // 600- status bar
 
+    // TODO(b/291315866): Tracking Bug
+    @JvmField val SIGNAL_CALLBACK_DEPRECATION = unreleasedFlag("signal_callback_deprecation")
+
     // TODO(b/265892345): Tracking Bug
     val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip")
 
@@ -391,7 +407,7 @@
 
     // TODO(b/290676905): Tracking Bug
     val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS =
-        unreleasedFlag("new_shade_carrier_group_mobile_icons")
+        unreleasedFlag("new_shade_carrier_group_mobile_icons", teamfood = true)
 
     // 700 - dialer/calls
     // TODO(b/254512734): Tracking Bug
@@ -489,11 +505,6 @@
 
     @Keep
     @JvmField
-    val WM_DESKTOP_WINDOWING =
-        sysPropBooleanFlag("persist.wm.debug.desktop_mode", default = false)
-
-    @Keep
-    @JvmField
     val WM_CAPTION_ON_SHELL =
         sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true)
 
@@ -625,15 +636,33 @@
     val CLIPBOARD_SHARED_TRANSITIONS =
             unreleasedFlag("clipboard_shared_transitions", teamfood = true)
 
+    /**
+     * Whether the scene container (Flexiglass) is enabled. Note that [SCENE_CONTAINER] should be
+     * checked and toggled together with [SCENE_CONTAINER_ENABLED] so that ProGuard can remove
+     * unused code from our APK at compile time.
+     */
     // TODO(b/283300105): Tracking Bug
-    @JvmField val SCENE_CONTAINER = unreleasedFlag("scene_container")
+    @JvmField val SCENE_CONTAINER_ENABLED = false
+    @Deprecated(
+        message = """
+            Do not use this flag directly. Please use
+            [com.android.systemui.scene.shared.flag.SceneContainerFlags#isEnabled].
+
+            (Not really deprecated but using this as a simple way to bring attention to the above).
+        """,
+        replaceWith = ReplaceWith(
+            "com.android.systemui.scene.shared.flag.SceneContainerFlags#isEnabled",
+        ),
+        level = DeprecationLevel.WARNING,
+    )
+    @JvmField val SCENE_CONTAINER = resourceBooleanFlag(
+        R.bool.config_sceneContainerFrameworkEnabled,
+        "scene_container",
+    )
 
     // 1900
     @JvmField val NOTE_TASKS = releasedFlag("keycode_flag")
 
-    // 2000 - device controls
-    @JvmField val APP_PANELS_ALL_APPS_ALLOWED = releasedFlag("app_panels_all_apps_allowed")
-
     // 2200 - biometrics (udfps, sfps, BiometricPrompt, etc.)
     // TODO(b/259264861): Tracking Bug
     @JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag("udfps_new_touch_detection")
@@ -654,6 +683,10 @@
     val WARN_ON_BLOCKING_BINDER_TRANSACTIONS =
         unreleasedFlag("warn_on_blocking_binder_transactions")
 
+    @JvmField
+    val COROUTINE_TRACING =
+        unreleasedFlag("coroutine_tracing")
+
     // TODO(b/283071711): Tracking bug
     @JvmField
     val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK =
@@ -662,6 +695,10 @@
     // TODO:(b/283203305): Tracking bug
     @JvmField val TRIM_FONT_CACHES_AT_UNLOCK = unreleasedFlag("trim_font_caches_on_unlock")
 
+    // TODO(b/298380520): Tracking Bug
+    @JvmField
+    val USER_TRACKER_BACKGROUND_CALLBACKS = unreleasedFlag("user_tracker_background_callbacks")
+
     // 2700 - unfold transitions
     // TODO(b/265764985): Tracking Bug
     @Keep
@@ -686,7 +723,7 @@
     @JvmField val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag("keyboard_backlight_indicator")
 
     // TODO(b/277192623): Tracking Bug
-    @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = false)
+    @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = true)
 
     // TODO(b/277201412): Tracking Bug
     @JvmField
@@ -752,15 +789,15 @@
 
     /** Enable the Compose implementation of the PeopleSpaceActivity. */
     @JvmField
-    val COMPOSE_PEOPLE_SPACE = unreleasedFlag("compose_people_space")
+    val COMPOSE_PEOPLE_SPACE = unreleasedFlag("compose_people_space", teamfood = true)
 
     /** Enable the Compose implementation of the Quick Settings footer actions. */
     @JvmField
-    val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag("compose_qs_footer_actions")
+    val COMPOSE_QS_FOOTER_ACTIONS = unreleasedFlag("compose_qs_footer_actions", teamfood = true)
 
     /** Enable the share wifi button in Quick Settings internet dialog. */
     @JvmField
-    val SHARE_WIFI_QS_BUTTON = unreleasedFlag("share_wifi_qs_button")
+    val SHARE_WIFI_QS_BUTTON = unreleasedFlag("share_wifi_qs_button", teamfood = true)
 
     /** Enable haptic slider component in the brightness slider */
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
index c41b5e4..2856011 100644
--- a/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/graphics/ImageLoader.kt
@@ -366,6 +366,52 @@
         }
     }
 
+    /**
+     * Obtains the image size from the image header, without decoding the full image.
+     *
+     * @param icon an [Icon] representing the source of the image
+     * @return the [Size] if it could be determined from the image header, or `null` otherwise
+     */
+    suspend fun loadSize(icon: Icon, context: Context): Size? =
+        withContext(backgroundDispatcher) { loadSizeSync(icon, context) }
+
+    /**
+     * Obtains the image size from the image header, without decoding the full image.
+     *
+     * @param icon an [Icon] representing the source of the image
+     * @return the [Size] if it could be determined from the image header, or `null` otherwise
+     */
+    @WorkerThread
+    fun loadSizeSync(icon: Icon, context: Context): Size? {
+        return when (icon.type) {
+            Icon.TYPE_URI,
+            Icon.TYPE_URI_ADAPTIVE_BITMAP -> {
+                val source = ImageDecoder.createSource(context.contentResolver, icon.uri)
+                loadSizeSync(source)
+            }
+            else -> null
+        }
+    }
+
+    /**
+     * Obtains the image size from the image header, without decoding the full image.
+     *
+     * @param source [ImageDecoder.Source] of the image
+     * @return the [Size] if it could be determined from the image header, or `null` otherwise
+     */
+    @WorkerThread
+    fun loadSizeSync(source: ImageDecoder.Source): Size? {
+        return try {
+            ImageDecoder.decodeHeader(source).size
+        } catch (e: IOException) {
+            Log.w(TAG, "Failed to load source $source", e)
+            return null
+        } catch (e: DecodeException) {
+            Log.w(TAG, "Failed to decode source $source", e)
+            return null
+        }
+    }
+
     companion object {
         const val TAG = "ImageLoader"
 
@@ -452,7 +498,7 @@
          * originate from other processes so we need to make sure we load them from the right
          * package source.
          *
-         * @return [Resources] to load the icon drawble or null if icon doesn't carry a resource or
+         * @return [Resources] to load the icon drawable or null if icon doesn't carry a resource or
          *   the resource package couldn't be resolved.
          */
         @WorkerThread
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderEventProducer.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderEventProducer.kt
new file mode 100644
index 0000000..629b361
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderEventProducer.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.haptics.slider
+
+import android.widget.SeekBar
+import android.widget.SeekBar.OnSeekBarChangeListener
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+
+/** An event producer for a Seekable element such as the Android [SeekBar] */
+class SeekableSliderEventProducer : SliderEventProducer, OnSeekBarChangeListener {
+
+    /** The current event reported by a SeekBar */
+    private val _currentEvent = MutableStateFlow(SliderEvent(SliderEventType.NOTHING, 0f))
+
+    override fun produceEvents(): Flow<SliderEvent> = _currentEvent.asStateFlow()
+
+    override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+        val eventType =
+            if (fromUser) SliderEventType.PROGRESS_CHANGE_BY_USER
+            else SliderEventType.PROGRESS_CHANGE_BY_PROGRAM
+
+        _currentEvent.value = SliderEvent(eventType, normalizeProgress(seekBar, progress))
+    }
+
+    /**
+     * Normalize the integer progress of a SeekBar to the range from 0F to 1F.
+     *
+     * @param[seekBar] The SeekBar that reports a progress.
+     * @param[progress] The integer progress of the SeekBar within its min and max values.
+     * @return The progress in the range from 0F to 1F.
+     */
+    private fun normalizeProgress(seekBar: SeekBar, progress: Int): Float {
+        if (seekBar.max == seekBar.min) {
+            return 1.0f
+        }
+        val range = seekBar.max - seekBar.min
+        return (progress - seekBar.min) / range.toFloat()
+    }
+
+    override fun onStartTrackingTouch(seekBar: SeekBar) {
+        _currentEvent.update { previousEvent ->
+            SliderEvent(SliderEventType.STARTED_TRACKING_TOUCH, previousEvent.currentProgress)
+        }
+    }
+
+    override fun onStopTrackingTouch(seekBar: SeekBar) {
+        _currentEvent.update { previousEvent ->
+            SliderEvent(SliderEventType.STOPPED_TRACKING_TOUCH, previousEvent.currentProgress)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEvent.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEvent.kt
new file mode 100644
index 0000000..1377b29
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEvent.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.haptics.slider
+
+import androidx.annotation.FloatRange
+
+/**
+ * An event arising from a slider.
+ *
+ * @property[type] The type of event. Must be one of [SliderEventType].
+ * @property[currentProgress] The current progress of the slider normalized to the range between 0F
+ *   and 1F (inclusive).
+ */
+data class SliderEvent(
+    val type: SliderEventType,
+    @FloatRange(from = 0.0, to = 1.0) val currentProgress: Float
+)
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEventProducer.kt
similarity index 62%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEventProducer.kt
index 24064b1..8b17e86 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEventProducer.kt
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.ui.composable
+package com.android.systemui.haptics.slider
 
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
+import kotlinx.coroutines.flow.Flow
 
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+/** Defines a producer of [SliderEvent] to be consumed as a [Flow] */
+interface SliderEventProducer {
+
+    /**
+     * Produce a stream of [SliderEvent]
+     *
+     * @return A [Flow] of [SliderEvent] produced from the operation of a slider.
+     */
+    fun produceEvents(): Flow<SliderEvent>
 }
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEventType.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEventType.kt
new file mode 100644
index 0000000..413e277
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderEventType.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.haptics.slider
+
+/** The type of a [SliderEvent]. */
+enum class SliderEventType {
+    /* No event. */
+    NOTHING,
+    /* The slider has captured a touch input and is tracking touch events. */
+    STARTED_TRACKING_TOUCH,
+    /* The slider progress is changing due to user touch input. */
+    PROGRESS_CHANGE_BY_USER,
+    /* The slider progress is changing programmatically. */
+    PROGRESS_CHANGE_BY_PROGRAM,
+    /* The slider has stopped tracking touch events. */
+    STOPPED_TRACKING_TOUCH,
+    /* The external (not touch) stimulus that was modifying the slider progress has stopped. */
+    EXTERNAL_STIMULUS_RELEASE,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 9d2771e..f6add9c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -298,18 +298,18 @@
     }
 
     @Inject
-    public KeyguardService(KeyguardViewMediator keyguardViewMediator,
-                           KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
-                           ScreenOnCoordinator screenOnCoordinator,
-                           ShellTransitions shellTransitions,
-                           DisplayTracker displayTracker,
-                           WindowManagerLockscreenVisibilityViewModel
-                                   wmLockscreenVisibilityViewModel,
-                           WindowManagerLockscreenVisibilityManager wmLockscreenVisibilityManager,
-                           KeyguardSurfaceBehindViewModel keyguardSurfaceBehindViewModel,
-                           KeyguardSurfaceBehindParamsApplier keyguardSurfaceBehindAnimator,
-                           @Application CoroutineScope scope,
-                           FeatureFlags featureFlags) {
+    public KeyguardService(
+            KeyguardViewMediator keyguardViewMediator,
+            KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
+            ScreenOnCoordinator screenOnCoordinator,
+            ShellTransitions shellTransitions,
+            DisplayTracker displayTracker,
+            WindowManagerLockscreenVisibilityViewModel wmLockscreenVisibilityViewModel,
+            WindowManagerLockscreenVisibilityManager wmLockscreenVisibilityManager,
+            KeyguardSurfaceBehindViewModel keyguardSurfaceBehindViewModel,
+            KeyguardSurfaceBehindParamsApplier keyguardSurfaceBehindAnimator,
+            @Application CoroutineScope scope,
+            FeatureFlags featureFlags) {
         super();
         mKeyguardViewMediator = keyguardViewMediator;
         mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 1cd8795..257006e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -17,10 +17,15 @@
 
 package com.android.systemui.keyguard
 
+import android.content.Context
 import android.content.res.Configuration
+import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import com.android.keyguard.KeyguardStatusView
 import com.android.keyguard.KeyguardStatusViewController
+import com.android.keyguard.LockIconView
+import com.android.keyguard.LockIconViewController
 import com.android.keyguard.dagger.KeyguardStatusViewComponent
 import com.android.systemui.CoreStartable
 import com.android.systemui.R
@@ -37,6 +42,7 @@
 import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder
+import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.keyguard.ui.view.layout.KeyguardBlueprintCommandListener
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardAmbientIndicationViewModel
@@ -92,6 +98,9 @@
     private val communalWidgetViewModel: CommunalWidgetViewModel,
     private val communalWidgetViewAdapter: CommunalWidgetViewAdapter,
     private val notificationStackScrollerLayoutController: NotificationStackScrollLayoutController,
+    private val context: Context,
+    private val keyguardIndicationController: KeyguardIndicationController,
+    private val lockIconViewController: LockIconViewController,
 ) : CoreStartable {
 
     private var rootViewHandle: DisposableHandle? = null
@@ -100,22 +109,41 @@
     private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
     private var ambientIndicationAreaHandle: KeyguardAmbientIndicationAreaViewBinder.Binding? = null
     private var settingsPopupMenuHandle: DisposableHandle? = null
-    private var keyguardStatusViewController: KeyguardStatusViewController? = null
+    var keyguardStatusViewController: KeyguardStatusViewController? = null
+        get() {
+            if (field == null) {
+                val statusViewComponent =
+                    keyguardStatusViewComponentFactory.build(
+                        LayoutInflater.from(context).inflate(R.layout.keyguard_status_view, null)
+                            as KeyguardStatusView
+                    )
+                val controller = statusViewComponent.keyguardStatusViewController
+                controller.init()
+                field = controller
+            }
+
+            return field
+        }
 
     override fun start() {
         bindKeyguardRootView()
-        val notificationPanel =
-            notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup
-        unbindKeyguardBottomArea(notificationPanel)
-        bindIndicationArea()
-        bindLockIconView(notificationPanel)
-        bindKeyguardStatusView(notificationPanel)
-        setupNotificationStackScrollLayout(notificationPanel)
-        bindLeftShortcut()
-        bindRightShortcut()
-        bindAmbientIndicationArea()
-        bindSettingsPopupMenu()
-        bindCommunalWidgetArea()
+        if (featureFlags.isEnabled(Flags.LAZY_INFLATE_KEYGUARD)) {
+            keyguardRootView.removeAllViews()
+            initializeViews()
+        } else {
+            val notificationPanel =
+                notificationShadeWindowView.requireViewById(R.id.notification_panel) as ViewGroup
+            unbindKeyguardBottomArea(notificationPanel)
+            bindIndicationArea()
+            bindLockIconView(notificationPanel)
+            bindKeyguardStatusView(notificationPanel)
+            setupNotificationStackScrollLayout(notificationPanel)
+            bindLeftShortcut()
+            bindRightShortcut()
+            bindAmbientIndicationArea()
+            bindSettingsPopupMenu()
+            bindCommunalWidgetArea()
+        }
 
         KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel)
         keyguardBlueprintCommandListener.start()
@@ -164,6 +192,14 @@
             )
     }
 
+    /** Initialize views so that corresponding controllers have a view set. */
+    private fun initializeViews() {
+        val indicationArea = KeyguardIndicationArea(context, null)
+        keyguardIndicationController.setIndicationArea(indicationArea)
+
+        lockIconViewController.setLockIconView(LockIconView(context, null))
+    }
+
     private fun bindKeyguardRootView() {
         rootViewHandle?.dispose()
         rootViewHandle =
@@ -186,6 +222,9 @@
             keyguardRootView.findViewById<View?>(R.id.lock_icon_view)?.let {
                 keyguardRootView.removeView(it)
             }
+            legacyParent.requireViewById<LockIconView>(R.id.lock_icon_view).let {
+                lockIconViewController.setLockIconView(it)
+            }
         }
     }
 
@@ -307,6 +346,5 @@
      * Temporary, to allow NotificationPanelViewController to use the same instance while code is
      * migrated: b/288242803
      */
-    fun getKeyguardStatusViewController() = keyguardStatusViewController
     fun getKeyguardRootView() = keyguardRootView
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e983a05..2b4dc81 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -3207,7 +3207,7 @@
      *                        visible
      */
     public void exitKeyguardAndFinishSurfaceBehindRemoteAnimation(boolean showKeyguard) {
-        Log.d(TAG, "onKeyguardExitRemoteAnimationFinished");
+        Log.d(TAG, "exitKeyguardAndFinishSurfaceBehindRemoteAnimation");
         if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) {
             Log.d(TAG, "skip onKeyguardExitRemoteAnimationFinished showKeyguard=" + showKeyguard
                     + " surfaceAnimationRunning=" + mSurfaceBehindRemoteAnimationRunning
@@ -3222,6 +3222,13 @@
 
         // Post layout changes to the next frame, so we don't hang at the end of the animation.
         DejankUtils.postAfterTraversal(() -> {
+            if (!mPM.isInteractive()) {
+                Log.e(TAG, "exitKeyguardAndFinishSurfaceBehindRemoteAnimation#postAfterTraversal" +
+                        "Not interactive after traversal. Don't hide the keyguard. This means we " +
+                        "re-locked the device during unlock.");
+                return;
+            }
+
             onKeyguardExitFinished();
 
             if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
index 7234757..f91ae74 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt
@@ -17,13 +17,10 @@
 
 package com.android.systemui.keyguard.data.repository
 
-import android.view.View
-import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.core.view.children
 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.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT
 import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule
 import java.io.PrintWriter
@@ -95,26 +92,3 @@
         blueprintIdMap.forEach { entry -> pw.println("${entry.key}") }
     }
 }
-
-/** Determines the constraints for the ConstraintSet in the lockscreen root view. */
-interface KeyguardBlueprint {
-    val id: String
-    val shouldRemoveUnconstrainedViews: Boolean
-        get() = true
-
-    fun apply(constraintLayout: ConstraintSet)
-    fun removeUnConstrainedViews(constraintLayout: ConstraintLayout, constraintSet: ConstraintSet) {
-        constraintLayout.children
-            .map { it.id }
-            .filterNot { constraintSet.knownIds.contains(it) }
-            .forEach { constraintSet.setVisibility(it, View.GONE) }
-    }
-}
-
-/**
- * Lower level modules that determine constraints for a particular section in the lockscreen root
- * view.
- */
-interface KeyguardSection {
-    fun apply(constraintSet: ConstraintSet)
-}
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 42cd3a5..d399e4c 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
@@ -158,7 +158,7 @@
     val lastDozeTapToWakePosition: StateFlow<Point?>
 
     /** Observable for the [StatusBarState] */
-    val statusBarState: Flow<StatusBarState>
+    val statusBarState: StateFlow<StatusBarState>
 
     /** Observable for device wake/sleep state */
     val wakefulness: StateFlow<WakefulnessModel>
@@ -520,23 +520,29 @@
         return keyguardBypassController.bypassEnabled
     }
 
-    override val statusBarState: Flow<StatusBarState> = conflatedCallbackFlow {
-        val callback =
-            object : StatusBarStateController.StateListener {
-                override fun onStateChanged(state: Int) {
-                    trySendWithFailureLogging(statusBarStateIntToObject(state), TAG, "state")
-                }
+    // TODO(b/297345631): Expose this at the interactor level instead so that it can be powered by
+    // [SceneInteractor] when scenes are ready.
+    override val statusBarState: StateFlow<StatusBarState> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : StatusBarStateController.StateListener {
+                        override fun onStateChanged(state: Int) {
+                            trySendWithFailureLogging(
+                                statusBarStateIntToObject(state),
+                                TAG,
+                                "state"
+                            )
+                        }
+                    }
+
+                statusBarStateController.addCallback(callback)
+                awaitClose { statusBarStateController.removeCallback(callback) }
             }
-
-        statusBarStateController.addCallback(callback)
-        trySendWithFailureLogging(
-            statusBarStateIntToObject(statusBarStateController.getState()),
-            TAG,
-            "initial state"
-        )
-
-        awaitClose { statusBarStateController.removeCallback(callback) }
-    }
+            .stateIn(
+                scope,
+                SharingStarted.Eagerly,
+                statusBarStateIntToObject(statusBarStateController.state)
+            )
 
     override val biometricUnlockState: Flow<BiometricUnlockModel> = conflatedCallbackFlow {
         fun dispatchUpdate() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index ff0db34..714add4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -50,14 +50,28 @@
         listenForOccludedToAodOrDozing()
         listenForOccludedToGone()
         listenForOccludedToAlternateBouncer()
+        listenForOccludedToPrimaryBouncer()
+    }
+
+    private fun listenForOccludedToPrimaryBouncer() {
+        scope.launch {
+            keyguardInteractor.primaryBouncerShowing
+                .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+                .collect { (isBouncerShowing, lastStartedTransitionStep) ->
+                    if (
+                        isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.OCCLUDED
+                    ) {
+                        startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
+                    }
+                }
+        }
     }
 
     private fun listenForOccludedToDreaming() {
         scope.launch {
             keyguardInteractor.isAbleToDream
                 .sample(transitionInteractor.finishedKeyguardState, ::Pair)
-                .collect { pair ->
-                    val (isAbleToDream, keyguardState) = pair
+                .collect { (isAbleToDream, keyguardState) ->
                     if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) {
                         startTransitionTo(KeyguardState.DREAMING)
                     }
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 e13f675..5727857 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
@@ -15,6 +15,8 @@
  *
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.keyguard.domain.interactor
 
 import android.app.StatusBarManager
@@ -42,10 +44,15 @@
 import com.android.systemui.keyguard.shared.model.ScreenModel
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
+import javax.inject.Provider
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
@@ -71,35 +78,46 @@
     private val repository: KeyguardRepository,
     private val commandQueue: CommandQueue,
     featureFlags: FeatureFlags,
+    sceneContainerFlags: SceneContainerFlags,
     bouncerRepository: KeyguardBouncerRepository,
     configurationRepository: ConfigurationRepository,
     shadeRepository: ShadeRepository,
+    sceneInteractorProvider: Provider<SceneInteractor>,
 ) {
     /** Position information for the shared notification container. */
     val sharedNotificationContainerPosition =
         MutableStateFlow(SharedNotificationContainerPosition())
+
     /**
      * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
      * all.
      */
     val dozeAmount: Flow<Float> = repository.linearDozeAmount
+
     /** Whether the system is in doze mode. */
     val isDozing: Flow<Boolean> = repository.isDozing
+
     /** Receive an event for doze time tick */
     val dozeTimeTick: Flow<Long> = repository.dozeTimeTick
+
     /** Whether Always-on Display mode is available. */
     val isAodAvailable: Flow<Boolean> = repository.isAodAvailable
+
     /** Doze transition information. */
     val dozeTransitionModel: Flow<DozeTransitionModel> = repository.dozeTransitionModel
+
     /**
      * Whether the system is dreaming. [isDreaming] will be always be true when [isDozing] is true,
      * but not vice-versa.
      */
     val isDreaming: Flow<Boolean> = repository.isDreaming
+
     /** Whether the system is dreaming with an overlay active */
     val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay
+
     /** Whether the system is dreaming and the active dream is hosted in lockscreen */
     val isActiveDreamLockscreenHosted: StateFlow<Boolean> = repository.isActiveDreamLockscreenHosted
+
     /** Event for when the camera gesture is detected */
     val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
         val callback =
@@ -148,18 +166,25 @@
 
     /** Whether the keyguard is showing or not. */
     val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
+
     /** Whether the keyguard is unlocked or not. */
     val isKeyguardUnlocked: Flow<Boolean> = repository.isKeyguardUnlocked
+
     /** Whether the keyguard is occluded (covered by an activity). */
     val isKeyguardOccluded: Flow<Boolean> = repository.isKeyguardOccluded
+
     /** Whether the keyguard is going away. */
     val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
+
     /** Whether the primary bouncer is showing or not. */
     val primaryBouncerShowing: Flow<Boolean> = bouncerRepository.primaryBouncerShow
+
     /** Whether the alternate bouncer is showing or not. */
     val alternateBouncerShowing: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
+
     /** Observable for the [StatusBarState] */
     val statusBarState: Flow<StatusBarState> = repository.statusBarState
+
     /**
      * Observable for [BiometricUnlockModel] when biometrics like face or any fingerprint (rear,
      * side, under display) is used to unlock the device.
@@ -171,7 +196,7 @@
         combine(isKeyguardShowing, isKeyguardOccluded) { showing, occluded -> showing && !occluded }
 
     /** Whether camera is launched over keyguard. */
-    var isSecureCameraActive =
+    val isSecureCameraActive: Flow<Boolean> by lazy {
         if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
             combine(
                     isKeyguardVisible,
@@ -188,6 +213,7 @@
         } else {
             flowOf(false)
         }
+    }
 
     /** The approximate location on the screen of the fingerprint sensor, if one is available. */
     val fingerprintSensorLocation: Flow<Point?> = repository.fingerprintSensorLocation
@@ -224,11 +250,29 @@
         }
 
     /** Whether to animate the next doze mode transition. */
-    val animateDozingTransitions: Flow<Boolean> = repository.animateBottomAreaDozingTransitions
+    val animateDozingTransitions: Flow<Boolean> by lazy {
+        if (sceneContainerFlags.isEnabled()) {
+            sceneInteractorProvider
+                .get()
+                .transitioningTo
+                .map { it == SceneKey.Lockscreen }
+                .distinctUntilChanged()
+                .flatMapLatest { isTransitioningToLockscreenScene ->
+                    if (isTransitioningToLockscreenScene) {
+                        flowOf(false)
+                    } else {
+                        repository.animateBottomAreaDozingTransitions
+                    }
+                }
+        } else {
+            repository.animateBottomAreaDozingTransitions
+        }
+    }
 
     fun dozeTransitionTo(vararg states: DozeStateModel): Flow<DozeTransitionModel> {
         return dozeTransitionModel.filter { states.contains(it.to) }
     }
+
     fun isKeyguardShowing(): Boolean {
         return repository.isKeyguardShowing()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt
new file mode 100644
index 0000000..35a9aae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardBlueprint.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.shared.model
+
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+
+/** Determines the constraints for the ConstraintSet in the lockscreen root view. */
+interface KeyguardBlueprint {
+    val id: String
+    val sections: Set<KeyguardSection>
+
+    /**
+     * Add views to new blueprint.
+     *
+     * Finds sections that did not exist in the previous blueprint and add the corresponding views.
+     *
+     * @param previousBluePrint: KeyguardBlueprint the blueprint we are transitioning from.
+     */
+    fun addViews(previousBlueprint: KeyguardBlueprint?, constraintLayout: ConstraintLayout) {
+        sections.subtract((previousBlueprint?.sections ?: setOf()).toSet()).forEach {
+            it.addViews(constraintLayout)
+            it.bindData(constraintLayout)
+        }
+    }
+
+    /**
+     * Remove views of old blueprint.
+     *
+     * Finds sections that are no longer in the next blueprint and remove the corresponding views.
+     *
+     * @param nextBluePrint: KeyguardBlueprint the blueprint we will transition to.
+     */
+    fun removeViews(nextBlueprint: KeyguardBlueprint, constraintLayout: ConstraintLayout) {
+        sections.subtract(nextBlueprint.sections).forEach { it.removeViews(constraintLayout) }
+    }
+
+    fun applyConstraints(constraintSet: ConstraintSet) {
+        sections.forEach { it.applyConstraints(constraintSet) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt
new file mode 100644
index 0000000..48a2146
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardSection.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.shared.model
+
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+
+/**
+ * Lower level modules that determine constraints for a particular section in the lockscreen root
+ * view.
+ */
+abstract class KeyguardSection {
+    /** Adds the views to the root view. */
+    abstract fun addViews(constraintLayout: ConstraintLayout)
+    /** Binds the views to data. */
+    abstract fun bindData(constraintLayout: ConstraintLayout)
+    /** Applies layout constraints to the view in respect to the root view. */
+    abstract fun applyConstraints(constraintSet: ConstraintSet)
+    /** Removes views and does any data binding destruction. */
+    abstract fun removeViews(constraintLayout: ConstraintLayout)
+
+    /**
+     * Defines equality as same class.
+     *
+     * This is to enable set operations to be done as an optimization to blueprint transitions.
+     */
+    override fun equals(other: Any?): Boolean {
+        other?.let { other ->
+            return this::class == other::class
+        }
+        return false
+    }
+
+    /**
+     * Defines hashcode as class.
+     *
+     * This is to enable set operations to be done as an optimization to blueprint transitions.
+     */
+    override fun hashCode(): Int {
+        return this::class.hashCode()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
index fb685da..c8a04fd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
@@ -19,18 +19,20 @@
 import android.os.PowerManager
 
 /** The reason we're waking up or going to sleep, such as pressing the power button. */
-enum class WakeSleepReason {
+enum class WakeSleepReason(
+    val isTouch: Boolean,
+) {
     /** The physical power button was pressed to wake up or sleep the device. */
-    POWER_BUTTON,
+    POWER_BUTTON(isTouch = false),
 
     /** The user has tapped or double tapped to wake the screen. */
-    TAP,
+    TAP(isTouch = true),
 
     /** The user performed some sort of gesture to wake the screen. */
-    GESTURE,
+    GESTURE(isTouch = true),
 
     /** Something else happened to wake up or sleep the device. */
-    OTHER;
+    OTHER(isTouch = false);
 
     companion object {
         fun fromPowerManagerWakeReason(reason: Int): WakeSleepReason {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index e40c279..78b72a9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -36,16 +36,22 @@
                 repeatOnLifecycle(Lifecycle.State.CREATED) {
                     launch {
                         viewModel.blueprint.collect { blueprint ->
-                            Trace.beginSection("KeyguardBlueprintController#applyBlueprint")
+                            val prevBluePrint = viewModel.currentBluePrint
+                            Trace.beginSection("KeyguardBlueprint#applyBlueprint")
                             Log.d(TAG, "applying blueprint: $blueprint")
+                            // Add and remove views of sections that are not contained by the other.
+                            prevBluePrint?.removeViews(blueprint, constraintLayout)
+                            blueprint.addViews(prevBluePrint, constraintLayout)
+
                             ConstraintSet().apply {
                                 clone(constraintLayout)
                                 val emptyLayout = ConstraintSet.Layout()
                                 knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
-                                blueprint?.apply(this)
-                                blueprint?.removeUnConstrainedViews(constraintLayout, this)
+                                blueprint.applyConstraints(this)
                                 applyTo(constraintLayout)
                             }
+
+                            viewModel.currentBluePrint = blueprint
                             Trace.endSection()
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 2814732..8b0b0ae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -78,6 +78,22 @@
                     }
 
                     if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+                        launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
+                    }
+
+                    if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+                        launch {
+                            viewModel.translationY.collect {
+                                val statusView =
+                                    view.requireViewById<View>(R.id.keyguard_status_view)
+                                statusView.translationY = it
+                            }
+                        }
+                    }
+                }
+
+                repeatOnLifecycle(Lifecycle.State.STARTED) {
+                    if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                         launch {
                             viewModel.keyguardRootViewVisibilityState.collect { visibilityState ->
                                 view.animate().cancel()
@@ -111,18 +127,6 @@
                                 }
                             }
                         }
-
-                        launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
-                    }
-
-                    if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
-                        launch {
-                            viewModel.translationY.collect {
-                                val statusView =
-                                    view.requireViewById<View>(R.id.keyguard_status_view)
-                                statusView.translationY = it
-                            }
-                        }
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 41c1c96..2cfc478 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -34,6 +34,7 @@
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.widget.FrameLayout
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.core.view.isInvisible
 import com.android.keyguard.ClockEventController
 import com.android.keyguard.KeyguardClockSwitch
@@ -45,12 +46,12 @@
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
-import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
@@ -109,6 +110,7 @@
     private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
     private val chipbarCoordinator: ChipbarCoordinator,
     private val keyguardStateController: KeyguardStateController,
+    private val defaultShortcutsSection: DefaultShortcutsSection,
 ) {
 
     val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
@@ -119,6 +121,7 @@
             KeyguardPreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES,
             false,
         )
+
     /** [shouldHideClock] here means that we never create and bind the clock views */
     private val shouldHideClock: Boolean =
         bundle.getBoolean(ClockPreviewConstants.KEY_HIDE_CLOCK, false)
@@ -176,7 +179,6 @@
 
             if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                 setupKeyguardRootView(rootView)
-                setupShortcuts(rootView)
             } else {
                 setUpBottomArea(rootView)
             }
@@ -348,14 +350,14 @@
                 FrameLayout.LayoutParams.MATCH_PARENT,
             ),
         )
-        KeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel)
-        keyguardBlueprintInteractor.refreshBlueprint()
+        setupShortcuts(keyguardRootView)
     }
 
-    private fun setupShortcuts(rootView: FrameLayout) {
+    private fun setupShortcuts(keyguardRootView: ConstraintLayout) {
+        defaultShortcutsSection.addShortcutViews(keyguardRootView)
         shortcutsBindings.add(
             KeyguardQuickAffordanceViewBinder.bind(
-                rootView.requireViewById(R.id.start_button),
+                keyguardRootView.requireViewById(R.id.start_button),
                 quickAffordancesCombinedViewModel.startButton,
                 keyguardRootViewModel.alpha,
                 falsingManager,
@@ -367,7 +369,7 @@
 
         shortcutsBindings.add(
             KeyguardQuickAffordanceViewBinder.bind(
-                rootView.requireViewById(R.id.end_button),
+                keyguardRootView.requireViewById(R.id.end_button),
                 quickAffordancesCombinedViewModel.endButton,
                 keyguardRootViewModel.alpha,
                 falsingManager,
@@ -516,11 +518,11 @@
             // is dark or a light.
             // TODO(b/277832214) we can potentially simplify this code by checking for
             // wallpaperColors being null in the if clause above and removing the many ?.
-            val wallpaperColorScheme =
-                wallpaperColors?.let { ColorScheme(it, /* darkTheme= */ false) }
+            val wallpaperColorScheme = wallpaperColors?.let { ColorScheme(it, darkTheme = false) }
             val lightClockColor = wallpaperColorScheme?.accent1?.s100
             val darkClockColor = wallpaperColorScheme?.accent2?.s600
-            /** Note that when [wallpaperColors] is null, isWallpaperDark is true. */
+
+            // Note that when [wallpaperColors] is null, isWallpaperDark is true.
             val isWallpaperDark: Boolean =
                 (wallpaperColors?.colorHints?.and(WallpaperColors.HINT_SUPPORTS_DARK_TEXT)) == 0
             clock.events.onSeedColorChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/LockscreenSceneModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/LockscreenSceneModule.kt
deleted file mode 100644
index c88737e..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/LockscreenSceneModule.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
-package com.android.systemui.keyguard.ui.view
-
-import android.view.View
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.KeyguardViewConfigurator
-import com.android.systemui.keyguard.qualifiers.KeyguardRootView
-import dagger.Module
-import dagger.Provides
-import javax.inject.Provider
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-
-@Module
-object LockscreenSceneModule {
-
-    @Provides
-    @SysUISingleton
-    @KeyguardRootView
-    fun viewProvider(
-        configurator: Provider<KeyguardViewConfigurator>,
-    ): () -> View {
-        return { configurator.get().getKeyguardRootView() }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
index 518df07..85b2b82 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprint.kt
@@ -17,12 +17,15 @@
 
 package com.android.systemui.keyguard.ui.view.layout.blueprints
 
-import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintLayout
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.repository.KeyguardBlueprint
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
@@ -39,24 +42,37 @@
 class DefaultKeyguardBlueprint
 @Inject
 constructor(
-    private val defaultIndicationAreaSection: DefaultIndicationAreaSection,
-    private val defaultLockIconSection: DefaultLockIconSection,
-    private val defaultShortcutsSection: DefaultShortcutsSection,
-    private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection,
-    private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
-    private val defaultStatusViewSection: DefaultStatusViewSection,
-    private val splitShadeGuidelines: SplitShadeGuidelines,
+    defaultIndicationAreaSection: DefaultIndicationAreaSection,
+    defaultLockIconSection: DefaultLockIconSection,
+    defaultShortcutsSection: DefaultShortcutsSection,
+    defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection,
+    defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
+    defaultStatusViewSection: DefaultStatusViewSection,
+    defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection,
+    splitShadeGuidelines: SplitShadeGuidelines,
+    private val featureFlags: FeatureFlags,
 ) : KeyguardBlueprint {
     override val id: String = DEFAULT
 
-    override fun apply(constraintSet: ConstraintSet) {
-        defaultIndicationAreaSection.apply(constraintSet)
-        defaultLockIconSection.apply(constraintSet)
-        defaultShortcutsSection.apply(constraintSet)
-        defaultAmbientIndicationAreaSection.apply(constraintSet)
-        defaultSettingsPopupMenuSection.apply(constraintSet)
-        defaultStatusViewSection.apply(constraintSet)
-        splitShadeGuidelines.apply(constraintSet)
+    override val sections =
+        setOf(
+            defaultIndicationAreaSection,
+            defaultLockIconSection,
+            defaultShortcutsSection,
+            defaultAmbientIndicationAreaSection,
+            defaultSettingsPopupMenuSection,
+            defaultStatusViewSection,
+            defaultNotificationStackScrollLayoutSection,
+            splitShadeGuidelines,
+        )
+
+    override fun addViews(
+        previousBlueprint: KeyguardBlueprint?,
+        constraintLayout: ConstraintLayout
+    ) {
+        if (featureFlags.isEnabled(Flags.LAZY_INFLATE_KEYGUARD)) {
+            super.addViews(previousBlueprint, constraintLayout)
+        }
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt
index 07f316b..fda4c3d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt
@@ -18,7 +18,7 @@
 package com.android.systemui.keyguard.ui.view.layout.blueprints
 
 import com.android.systemui.communal.ui.view.layout.blueprints.DefaultCommunalBlueprint
-import com.android.systemui.keyguard.data.repository.KeyguardBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import dagger.Binds
 import dagger.Module
 import dagger.multibindings.IntoSet
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
index 54c2796..bb3af6c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
@@ -17,16 +17,14 @@
 
 package com.android.systemui.keyguard.ui.view.layout.blueprints
 
-import androidx.constraintlayout.widget.ConstraintSet
-import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.repository.KeyguardBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdfpsSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
-import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
 import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
 import javax.inject.Inject
@@ -36,31 +34,28 @@
 class ShortcutsBesideUdfpsKeyguardBlueprint
 @Inject
 constructor(
-    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-    private val defaultIndicationAreaSection: DefaultIndicationAreaSection,
-    private val defaultLockIconSection: DefaultLockIconSection,
-    private val defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection,
-    private val defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
-    private val alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection,
-    private val defaultShortcutsSection: DefaultShortcutsSection,
-    private val defaultStatusViewSection: DefaultStatusViewSection,
-    private val splitShadeGuidelines: SplitShadeGuidelines,
+    defaultIndicationAreaSection: DefaultIndicationAreaSection,
+    defaultLockIconSection: DefaultLockIconSection,
+    defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection,
+    defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
+    alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection,
+    defaultStatusViewSection: DefaultStatusViewSection,
+    splitShadeGuidelines: SplitShadeGuidelines,
+    defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection,
 ) : KeyguardBlueprint {
     override val id: String = SHORTCUTS_BESIDE_UDFPS
 
-    override fun apply(constraintSet: ConstraintSet) {
-        defaultIndicationAreaSection.apply(constraintSet)
-        defaultLockIconSection.apply(constraintSet)
-        defaultAmbientIndicationAreaSection.apply(constraintSet)
-        defaultSettingsPopupMenuSection.apply(constraintSet)
-        if (keyguardUpdateMonitor.isUdfpsSupported) {
-            alignShortcutsToUdfpsSection.apply(constraintSet)
-        } else {
-            defaultShortcutsSection.apply(constraintSet)
-        }
-        defaultStatusViewSection.apply(constraintSet)
-        splitShadeGuidelines.apply(constraintSet)
-    }
+    override val sections =
+        setOf(
+            defaultIndicationAreaSection,
+            defaultLockIconSection,
+            defaultAmbientIndicationAreaSection,
+            defaultSettingsPopupMenuSection,
+            alignShortcutsToUdfpsSection,
+            defaultStatusViewSection,
+            defaultNotificationStackScrollLayoutSection,
+            splitShadeGuidelines,
+        )
 
     companion object {
         const val SHORTCUTS_BESIDE_UDFPS = "shortcutsBesideUdfps"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
index 156b9f3..79b7157 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AlignShortcutsToUdfpsSection.kt
@@ -18,20 +18,78 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.content.res.Resources
+import android.view.View
+import android.widget.ImageView
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.LEFT
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.RIGHT
 import androidx.constraintlayout.widget.ConstraintSet.TOP
+import androidx.core.content.res.ResourcesCompat
 import com.android.systemui.R
+import com.android.systemui.animation.view.LaunchableImageView
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.KeyguardIndicationController
+import com.android.systemui.statusbar.VibratorHelper
 import javax.inject.Inject
 
-class AlignShortcutsToUdfpsSection @Inject constructor(@Main private val resources: Resources) :
-    KeyguardSection {
-    override fun apply(constraintSet: ConstraintSet) {
+class AlignShortcutsToUdfpsSection
+@Inject
+constructor(
+    @Main private val resources: Resources,
+    private val featureFlags: FeatureFlags,
+    private val keyguardQuickAffordancesCombinedViewModel:
+        KeyguardQuickAffordancesCombinedViewModel,
+    private val keyguardRootViewModel: KeyguardRootViewModel,
+    private val falsingManager: FalsingManager,
+    private val indicationController: KeyguardIndicationController,
+    private val vibratorHelper: VibratorHelper,
+) : KeyguardSection() {
+    private var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
+    private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            addLeftShortcut(constraintLayout)
+            addRightShortcut(constraintLayout)
+        }
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            leftShortcutHandle =
+                KeyguardQuickAffordanceViewBinder.bind(
+                    constraintLayout.requireViewById(R.id.start_button),
+                    keyguardQuickAffordancesCombinedViewModel.startButton,
+                    keyguardRootViewModel.alpha,
+                    falsingManager,
+                    vibratorHelper,
+                ) {
+                    indicationController.showTransientIndication(it)
+                }
+            rightShortcutHandle =
+                KeyguardQuickAffordanceViewBinder.bind(
+                    constraintLayout.requireViewById(R.id.end_button),
+                    keyguardQuickAffordancesCombinedViewModel.endButton,
+                    keyguardRootViewModel.alpha,
+                    falsingManager,
+                    vibratorHelper,
+                ) {
+                    indicationController.showTransientIndication(it)
+                }
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         val width = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width)
         val height = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height)
 
@@ -51,4 +109,67 @@
             connect(R.id.end_button, BOTTOM, R.id.lock_icon_view, BOTTOM)
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        leftShortcutHandle?.destroy()
+        rightShortcutHandle?.destroy()
+        constraintLayout.removeView(R.id.start_button)
+        constraintLayout.removeView(R.id.end_button)
+    }
+
+    private fun addLeftShortcut(constraintLayout: ConstraintLayout) {
+        val padding =
+            constraintLayout.resources.getDimensionPixelSize(
+                R.dimen.keyguard_affordance_fixed_padding
+            )
+        val view =
+            LaunchableImageView(constraintLayout.context, null).apply {
+                id = R.id.start_button
+                scaleType = ImageView.ScaleType.FIT_CENTER
+                background =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_bg,
+                        context.theme
+                    )
+                foreground =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_selected_border,
+                        context.theme
+                    )
+                visibility = View.INVISIBLE
+                setPadding(padding, padding, padding, padding)
+            }
+        constraintLayout.addView(view)
+    }
+
+    private fun addRightShortcut(constraintLayout: ConstraintLayout) {
+        if (constraintLayout.findViewById<View>(R.id.end_button) != null) return
+
+        val padding =
+            constraintLayout.resources.getDimensionPixelSize(
+                R.dimen.keyguard_affordance_fixed_padding
+            )
+        val view =
+            LaunchableImageView(constraintLayout.context, null).apply {
+                id = R.id.end_button
+                scaleType = ImageView.ScaleType.FIT_CENTER
+                background =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_bg,
+                        context.theme
+                    )
+                foreground =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_selected_border,
+                        context.theme
+                    )
+                visibility = View.INVISIBLE
+                setPadding(padding, padding, padding, padding)
+            }
+        constraintLayout.addView(view)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt
index abf25a2..ce86e97 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultAmbientIndicationAreaSection.kt
@@ -17,7 +17,9 @@
 
 package com.android.systemui.keyguard.ui.view.layout.sections
 
+import android.view.LayoutInflater
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.END
@@ -28,13 +30,46 @@
 import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardAmbientIndicationAreaViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardAmbientIndicationViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
 import javax.inject.Inject
 
 class DefaultAmbientIndicationAreaSection
 @Inject
-constructor(private val keyguardUpdateMonitor: KeyguardUpdateMonitor) : KeyguardSection {
-    override fun apply(constraintSet: ConstraintSet) {
+constructor(
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val featureFlags: FeatureFlags,
+    private val keyguardAmbientIndicationViewModel: KeyguardAmbientIndicationViewModel,
+    private val keyguardRootViewModel: KeyguardRootViewModel,
+) : KeyguardSection() {
+    private var ambientIndicationAreaHandle: KeyguardAmbientIndicationAreaViewBinder.Binding? = null
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            val view =
+                LayoutInflater.from(constraintLayout.context)
+                    .inflate(R.layout.ambient_indication, constraintLayout, false)
+
+            constraintLayout.addView(view)
+        }
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            ambientIndicationAreaHandle =
+                KeyguardAmbientIndicationAreaViewBinder.bind(
+                    constraintLayout,
+                    keyguardAmbientIndicationViewModel,
+                    keyguardRootViewModel,
+                )
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         constraintSet.apply {
             constrainWidth(R.id.ambient_indication_container, MATCH_PARENT)
 
@@ -59,4 +94,10 @@
             }
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        ambientIndicationAreaHandle?.destroy()
+
+        constraintLayout.removeView(R.id.ambient_indication_container)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
index dee7ed5..a45223c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSection.kt
@@ -19,16 +19,53 @@
 
 import android.content.Context
 import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder
+import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
+import com.android.systemui.statusbar.KeyguardIndicationController
 import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
 
-class DefaultIndicationAreaSection @Inject constructor(private val context: Context) :
-    KeyguardSection {
+class DefaultIndicationAreaSection
+@Inject
+constructor(
+    private val context: Context,
+    private val keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel,
+    private val keyguardRootViewModel: KeyguardRootViewModel,
+    private val indicationController: KeyguardIndicationController,
+    private val featureFlags: FeatureFlags,
+) : KeyguardSection() {
     private val indicationAreaViewId = R.id.keyguard_indication_area
+    private var indicationAreaHandle: DisposableHandle? = null
 
-    override fun apply(constraintSet: ConstraintSet) {
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            val view = KeyguardIndicationArea(context, null)
+            constraintLayout.addView(view)
+        }
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            indicationAreaHandle =
+                KeyguardIndicationAreaBinder.bind(
+                    constraintLayout,
+                    keyguardIndicationAreaViewModel,
+                    keyguardRootViewModel,
+                    indicationController,
+                    featureFlags,
+                )
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         constraintSet.apply {
             constrainWidth(indicationAreaViewId, ViewGroup.LayoutParams.MATCH_PARENT)
             constrainHeight(indicationAreaViewId, ViewGroup.LayoutParams.WRAP_CONTENT)
@@ -53,4 +90,9 @@
             )
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        indicationAreaHandle?.dispose()
+        constraintLayout.removeView(indicationAreaViewId)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
index 461faec..3e91d93 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSection.kt
@@ -21,13 +21,20 @@
 import android.graphics.Point
 import android.graphics.Rect
 import android.util.DisplayMetrics
+import android.view.View
 import android.view.WindowManager
 import androidx.annotation.VisibleForTesting
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.LockIconView
+import com.android.keyguard.LockIconViewController
 import com.android.systemui.R
 import com.android.systemui.biometrics.AuthController
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.shade.NotificationPanelView
 import javax.inject.Inject
 
 class DefaultLockIconSection
@@ -37,16 +44,34 @@
     private val authController: AuthController,
     private val windowManager: WindowManager,
     private val context: Context,
-) : KeyguardSection {
+    private val notificationPanelView: NotificationPanelView,
+    private val featureFlags: FeatureFlags,
+    private val lockIconViewController: LockIconViewController,
+) : KeyguardSection() {
     private val lockIconViewId = R.id.lock_icon_view
 
-    override fun apply(constraintSet: ConstraintSet) {
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (!featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) {
+            return
+        }
+        notificationPanelView.findViewById<View>(R.id.lock_icon_view).let {
+            notificationPanelView.removeView(it)
+        }
+        val view = LockIconView(context, null).apply { id = R.id.lock_icon_view }
+        constraintLayout.addView(view)
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
+            lockIconViewController.setLockIconView(it)
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         val isUdfpsSupported = keyguardUpdateMonitor.isUdfpsSupported
         val scaleFactor: Float = authController.scaleFactor
         val mBottomPaddingPx =
             context.resources.getDimensionPixelSize(R.dimen.lock_icon_margin_bottom)
-        val mDefaultPaddingPx = context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding)
-        val scaledPadding: Int = (mDefaultPaddingPx * scaleFactor).toInt()
         val bounds = windowManager.currentWindowMetrics.bounds
         val widthPixels = bounds.right.toFloat()
         val heightPixels = bounds.bottom.toFloat()
@@ -57,12 +82,7 @@
 
         if (isUdfpsSupported) {
             authController.udfpsLocation?.let { udfpsLocation ->
-                centerLockIcon(
-                    udfpsLocation,
-                    authController.udfpsRadius,
-                    scaledPadding,
-                    constraintSet
-                )
+                centerLockIcon(udfpsLocation, authController.udfpsRadius, constraintSet)
             }
         } else {
             centerLockIcon(
@@ -71,19 +91,17 @@
                     (heightPixels - ((mBottomPaddingPx + lockIconRadiusPx) * scaleFactor)).toInt()
                 ),
                 lockIconRadiusPx * scaleFactor,
-                scaledPadding,
                 constraintSet,
             )
         }
     }
 
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        constraintLayout.removeView(R.id.lock_icon_view)
+    }
+
     @VisibleForTesting
-    internal fun centerLockIcon(
-        center: Point,
-        radius: Float,
-        drawablePadding: Int,
-        constraintSet: ConstraintSet
-    ) {
+    internal fun centerLockIcon(center: Point, radius: Float, constraintSet: ConstraintSet) {
         val sensorRect =
             Rect().apply {
                 set(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
new file mode 100644
index 0000000..59c5d78
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.view.View
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.R
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
+import javax.inject.Inject
+
+class DefaultNotificationStackScrollLayoutSection
+@Inject
+constructor(
+    private val featureFlags: FeatureFlags,
+    private val notificationPanelView: NotificationPanelView,
+    private val sharedNotificationContainer: SharedNotificationContainer,
+    private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+    private val controller: NotificationStackScrollLayoutController,
+) : KeyguardSection() {
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (!featureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            return
+        }
+        // This moves the existing NSSL view to a different parent, as the controller is a
+        // singleton and recreating it has other bad side effects
+        notificationPanelView.findViewById<View?>(R.id.notification_stack_scroller)?.let {
+            (it.parent as ViewGroup).removeView(it)
+            sharedNotificationContainer.addNotificationStackScrollLayout(it)
+        }
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_NSSL)) {
+            SharedNotificationContainerBinder.bind(
+                sharedNotificationContainer,
+                sharedNotificationContainerViewModel,
+                controller,
+            )
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {}
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
index ad1e4f8..b25f9af 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
@@ -18,20 +18,68 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.content.res.Resources
+import android.view.LayoutInflater
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
+import androidx.core.view.isVisible
 import com.android.systemui.R
+import com.android.systemui.animation.view.LaunchableLinearLayout
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardSettingsViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsMenuViewModel
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.VibratorHelper
 import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
 
-class DefaultSettingsPopupMenuSection @Inject constructor(@Main private val resources: Resources) :
-    KeyguardSection {
-    override fun apply(constraintSet: ConstraintSet) {
+class DefaultSettingsPopupMenuSection
+@Inject
+constructor(
+    @Main private val resources: Resources,
+    private val featureFlags: FeatureFlags,
+    private val keyguardSettingsMenuViewModel: KeyguardSettingsMenuViewModel,
+    private val vibratorHelper: VibratorHelper,
+    private val activityStarter: ActivityStarter,
+) : KeyguardSection() {
+    private var settingsPopupMenuHandle: DisposableHandle? = null
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            return
+        }
+        val view =
+            LayoutInflater.from(constraintLayout.context)
+                .inflate(R.layout.keyguard_settings_popup_menu, constraintLayout, false)
+                .apply {
+                    id = R.id.keyguard_settings_button
+                    isVisible = false
+                    alpha = 0f
+                } as LaunchableLinearLayout
+        constraintLayout.addView(view)
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            settingsPopupMenuHandle =
+                KeyguardSettingsViewBinder.bind(
+                    constraintLayout.requireViewById<View>(R.id.keyguard_settings_button),
+                    keyguardSettingsMenuViewModel,
+                    vibratorHelper,
+                    activityStarter,
+                )
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         val horizontalOffsetMargin =
             resources.getDimensionPixelSize(R.dimen.keyguard_affordance_horizontal_offset)
 
@@ -51,6 +99,12 @@
                 BOTTOM,
                 resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset)
             )
+            setVisibility(R.id.keyguard_settings_button, View.GONE)
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        settingsPopupMenuHandle?.dispose()
+        constraintLayout.removeView(R.id.keyguard_settings_button)
+    }
 }
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 db4653d..c498055 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
@@ -18,19 +18,77 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.content.res.Resources
+import android.view.View
+import android.widget.ImageView
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
 import androidx.constraintlayout.widget.ConstraintSet.LEFT
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.RIGHT
+import androidx.core.content.res.ResourcesCompat
 import com.android.systemui.R
+import com.android.systemui.animation.view.LaunchableImageView
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.KeyguardIndicationController
+import com.android.systemui.statusbar.VibratorHelper
 import javax.inject.Inject
 
-class DefaultShortcutsSection @Inject constructor(@Main private val resources: Resources) :
-    KeyguardSection {
-    override fun apply(constraintSet: ConstraintSet) {
+class DefaultShortcutsSection
+@Inject
+constructor(
+    @Main private val resources: Resources,
+    private val featureFlags: FeatureFlags,
+    private val keyguardQuickAffordancesCombinedViewModel:
+        KeyguardQuickAffordancesCombinedViewModel,
+    private val keyguardRootViewModel: KeyguardRootViewModel,
+    private val falsingManager: FalsingManager,
+    private val indicationController: KeyguardIndicationController,
+    private val vibratorHelper: VibratorHelper,
+) : KeyguardSection() {
+    private var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
+    private var rightShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            addLeftShortcut(constraintLayout)
+            addRightShortcut(constraintLayout)
+        }
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+            leftShortcutHandle =
+                KeyguardQuickAffordanceViewBinder.bind(
+                    constraintLayout.requireViewById(R.id.start_button),
+                    keyguardQuickAffordancesCombinedViewModel.startButton,
+                    keyguardRootViewModel.alpha,
+                    falsingManager,
+                    vibratorHelper,
+                ) {
+                    indicationController.showTransientIndication(it)
+                }
+            rightShortcutHandle =
+                KeyguardQuickAffordanceViewBinder.bind(
+                    constraintLayout.requireViewById(R.id.end_button),
+                    keyguardQuickAffordancesCombinedViewModel.endButton,
+                    keyguardRootViewModel.alpha,
+                    falsingManager,
+                    vibratorHelper,
+                ) {
+                    indicationController.showTransientIndication(it)
+                }
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         val width = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width)
         val height = resources.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height)
         val horizontalOffsetMargin =
@@ -50,4 +108,78 @@
             connect(R.id.end_button, BOTTOM, PARENT_ID, BOTTOM, verticalOffsetMargin)
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        leftShortcutHandle?.destroy()
+        rightShortcutHandle?.destroy()
+        constraintLayout.removeView(R.id.start_button)
+        constraintLayout.removeView(R.id.end_button)
+    }
+
+    private fun addLeftShortcut(constraintLayout: ConstraintLayout) {
+        val padding =
+            constraintLayout.resources.getDimensionPixelSize(
+                R.dimen.keyguard_affordance_fixed_padding
+            )
+        val view =
+            LaunchableImageView(constraintLayout.context, null).apply {
+                id = R.id.start_button
+                scaleType = ImageView.ScaleType.FIT_CENTER
+                background =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_bg,
+                        context.theme
+                    )
+                foreground =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_selected_border,
+                        context.theme
+                    )
+                visibility = View.INVISIBLE
+                setPadding(padding, padding, padding, padding)
+            }
+        constraintLayout.addView(view)
+    }
+
+    private fun addRightShortcut(constraintLayout: ConstraintLayout) {
+        if (constraintLayout.findViewById<View>(R.id.end_button) != null) return
+
+        val padding =
+            constraintLayout.resources.getDimensionPixelSize(
+                R.dimen.keyguard_affordance_fixed_padding
+            )
+        val view =
+            LaunchableImageView(constraintLayout.context, null).apply {
+                id = R.id.end_button
+                scaleType = ImageView.ScaleType.FIT_CENTER
+                background =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_bg,
+                        context.theme
+                    )
+                foreground =
+                    ResourcesCompat.getDrawable(
+                        context.resources,
+                        R.drawable.keyguard_bottom_affordance_selected_border,
+                        context.theme
+                    )
+                visibility = View.INVISIBLE
+                setPadding(padding, padding, padding, padding)
+            }
+        constraintLayout.addView(view)
+    }
+
+    /** Method to add shortcuts without applying any data binding. */
+    fun addShortcutViews(constraintLayout: ConstraintLayout) {
+        addLeftShortcut(constraintLayout)
+        addRightShortcut(constraintLayout)
+        ConstraintSet().apply {
+            clone(constraintLayout)
+            applyConstraints(this)
+            applyTo(constraintLayout)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
index f1f5973..b144f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultStatusViewSection.kt
@@ -18,23 +18,79 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.keyguard.KeyguardStatusView
+import com.android.keyguard.dagger.KeyguardStatusViewComponent
 import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.KeyguardViewConfigurator
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.media.controls.ui.KeyguardMediaController
+import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.shade.NotificationPanelViewController
 import com.android.systemui.util.LargeScreenUtils
 import com.android.systemui.util.Utils
+import dagger.Lazy
 import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-class DefaultStatusViewSection @Inject constructor(private val context: Context) : KeyguardSection {
+class DefaultStatusViewSection
+@Inject
+constructor(
+    private val context: Context,
+    private val featureFlags: FeatureFlags,
+    private val notificationPanelView: NotificationPanelView,
+    private val keyguardStatusViewComponentFactory: KeyguardStatusViewComponent.Factory,
+    private val keyguardViewConfigurator: Lazy<KeyguardViewConfigurator>,
+    private val notificationPanelViewController: Lazy<NotificationPanelViewController>,
+    private val keyguardMediaController: KeyguardMediaController,
+) : KeyguardSection() {
     private val statusViewId = R.id.keyguard_status_view
 
-    override fun apply(constraintSet: ConstraintSet) {
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (!featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+            return
+        }
+        // At startup, 2 views with the ID `R.id.keyguard_status_view` will be available.
+        // Disable one of them
+        notificationPanelView.findViewById<View>(statusViewId)?.let {
+            notificationPanelView.removeView(it)
+        }
+        val keyguardStatusView =
+            (LayoutInflater.from(context)
+                    .inflate(R.layout.keyguard_status_view, constraintLayout, false)
+                    as KeyguardStatusView)
+                .apply { clipChildren = false }
+        constraintLayout.addView(keyguardStatusView)
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {
+        if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+            constraintLayout.findViewById<KeyguardStatusView?>(R.id.keyguard_status_view)?.let {
+                val statusViewComponent = keyguardStatusViewComponentFactory.build(it)
+                val controller = statusViewComponent.keyguardStatusViewController
+                controller.init()
+                keyguardMediaController.attachSplitShadeContainer(
+                    it.requireViewById<ViewGroup>(R.id.status_view_media_container)
+                )
+                keyguardViewConfigurator.get().keyguardStatusViewController = controller
+                notificationPanelViewController.get().updateStatusBarViewController()
+            }
+        }
+    }
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         constraintSet.apply {
             constrainWidth(statusViewId, MATCH_CONSTRAINT)
             constrainHeight(statusViewId, WRAP_CONTENT)
@@ -52,4 +108,10 @@
             setMargin(statusViewId, TOP, margin)
         }
     }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        constraintLayout.removeView(statusViewId)
+        keyguardViewConfigurator.get().keyguardStatusViewController = null
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/Extensions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/Extensions.kt
new file mode 100644
index 0000000..94332d2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/Extensions.kt
@@ -0,0 +1,8 @@
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.view.View
+import androidx.constraintlayout.widget.ConstraintLayout
+
+internal fun ConstraintLayout.removeView(viewId: Int) {
+    findViewById<View?>(viewId)?.let { removeView(it) }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt
index 668b17f..5e3ea05 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeGuidelines.kt
@@ -17,24 +17,19 @@
 
 package com.android.systemui.keyguard.ui.view.layout.sections
 
-import android.content.Context
-import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
-import com.android.systemui.R
-import com.android.systemui.keyguard.data.repository.KeyguardSection
-import javax.inject.Inject
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
-import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
-import androidx.constraintlayout.widget.ConstraintSet.START
-import androidx.constraintlayout.widget.ConstraintSet.TOP
-import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.VERTICAL
+import com.android.systemui.R
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import javax.inject.Inject
 
-class SplitShadeGuidelines @Inject constructor(private val context: Context) :
-    KeyguardSection {
+class SplitShadeGuidelines @Inject constructor() : KeyguardSection() {
+    override fun addViews(constraintLayout: ConstraintLayout) {}
 
-    override fun apply(constraintSet: ConstraintSet) {
+    override fun bindData(constraintLayout: ConstraintLayout) {}
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
         constraintSet.apply {
             // For use on large screens, it will provide a guideline vertically in the center to
             // enable items to be aligned on the left or right sides
@@ -42,4 +37,6 @@
             setGuidelinePercent(R.id.split_shade_guideline, 0.5f)
         }
     }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
index 5e9e553..e2bfc36 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt
@@ -17,13 +17,13 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import javax.inject.Inject
 
-@SysUISingleton
 class KeyguardBlueprintViewModel
 @Inject
 constructor(keyguardBlueprintInteractor: KeyguardBlueprintInteractor) {
+    var currentBluePrint: KeyguardBlueprint? = null
     val blueprint = keyguardBlueprintInteractor.blueprint
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index 93c4902..05c9323 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
-import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.scene.shared.model.SceneKey
 import javax.inject.Inject
@@ -30,7 +29,7 @@
 @Inject
 constructor(
     authenticationInteractor: AuthenticationInteractor,
-    private val bouncerInteractor: BouncerInteractor,
+    val longPress: KeyguardLongPressViewModel,
 ) {
     /** The key of the scene we should switch to when swiping up. */
     val upDestinationSceneKey: Flow<SceneKey> =
@@ -41,9 +40,4 @@
                 SceneKey.Bouncer
             }
         }
-
-    /** Notifies that the lock button on the lock screen was clicked. */
-    fun onLockButtonClicked() {
-        bouncerInteractor.showOrUnlockDevice()
-    }
 }
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 5127d14..6c2ce7f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -80,6 +80,14 @@
         return factory.create("NotifHeadsUpLog", 1000);
     }
 
+    /** Provides a logging buffer for logs related to inflation of notifications. */
+    @Provides
+    @SysUISingleton
+    @NotifInflationLog
+    public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) {
+        return factory.create("NotifInflationLog", 100);
+    }
+
     /** Provides a logging buffer for notification interruption calculations. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInflationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInflationLog.java
new file mode 100644
index 0000000..9f201c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInflationLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for messages related to inflation of notifications. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface NotifInflationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 8f884d24..053c9b5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -206,6 +206,11 @@
 
     override fun bind(recentTasks: List<RecentTask>) {
         recentsViewController.bind(recentTasks)
+        if (!hasWorkProfile()) {
+            // Make sure to refresh the adapter, to show/hide the recents view depending on whether
+            // there are recents or not.
+            mMultiProfilePagerAdapter.personalListAdapter.notifyDataSetChanged()
+        }
     }
 
     override fun returnSelectedApp(launchCookie: IBinder) {
@@ -248,9 +253,20 @@
 
     override fun shouldGetOnlyDefaultActivities() = false
 
-    override fun shouldShowContentPreview() = true
+    override fun shouldShowContentPreview() =
+        if (hasWorkProfile()) {
+            // When the user has a work profile, we can always set this to true, and the layout is
+            // adjusted automatically, and hide the recents view.
+            true
+        } else {
+            // When there is no work profile, we should only show the content preview if there are
+            // recents, otherwise the collapsed app selector will look empty.
+            recentsViewController.hasRecentTasks
+        }
 
-    override fun shouldShowContentPreviewWhenEmpty(): Boolean = true
+    override fun shouldShowContentPreviewWhenEmpty() = shouldShowContentPreview()
+
+    private fun hasWorkProfile() = mMultiProfilePagerAdapter.count > 1
 
     override fun createMyUserIdProvider(): MyUserIdProvider =
         object : MyUserIdProvider() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index a9d2b30..4be572f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -55,7 +55,6 @@
 import com.android.systemui.flags.Flags;
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDevicePolicyResolver;
 import com.android.systemui.mediaprojection.devicepolicy.ScreenCaptureDisabledDialog;
-import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.screenrecord.MediaProjectionPermissionDialog;
 import com.android.systemui.screenrecord.ScreenShareOption;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -73,7 +72,6 @@
 
     private final FeatureFlags mFeatureFlags;
     private final Lazy<ScreenCaptureDevicePolicyResolver> mScreenCaptureDevicePolicyResolver;
-    private final ActivityStarter mActivityStarter;
 
     private String mPackageName;
     private int mUid;
@@ -89,10 +87,8 @@
 
     @Inject
     public MediaProjectionPermissionActivity(FeatureFlags featureFlags,
-            Lazy<ScreenCaptureDevicePolicyResolver> screenCaptureDevicePolicyResolver,
-            ActivityStarter activityStarter) {
+            Lazy<ScreenCaptureDevicePolicyResolver> screenCaptureDevicePolicyResolver) {
         mFeatureFlags = featureFlags;
-        mActivityStarter = activityStarter;
         mScreenCaptureDevicePolicyResolver = screenCaptureDevicePolicyResolver;
     }
 
@@ -313,16 +309,8 @@
                 // Start activity from the current foreground user to avoid creating a separate
                 // SystemUI process without access to recent tasks because it won't have
                 // WM Shell running inside.
-                // It is also important to make sure the shade is dismissed, otherwise users won't
-                // see the app selector.
                 mUserSelectingTask = true;
-                mActivityStarter.startActivity(
-                        intent,
-                        /* dismissShade= */ true,
-                        /* animationController= */ null,
-                        /* showOverLockscreenWhenLocked= */ false,
-                        UserHandle.of(ActivityManager.getCurrentUser())
-                );
+                startActivityAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error granting projection permission", e);
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 398dcf2..38a6a8f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -39,7 +39,6 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.Dumpable
 import com.android.systemui.R
-import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
@@ -59,6 +58,11 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.PageIndicator
 import com.android.systemui.shared.system.SysUiStatsLog
+import com.android.systemui.shared.system.SysUiStatsLog.SMARTSPACE_CARD_REPORTED
+import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD
+import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY as SSPACE_CARD_REPORTED__DREAM_OVERLAY
+import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN as SSPACE_CARD_REPORTED__LOCKSCREEN
+import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE
 import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
@@ -100,7 +104,6 @@
     @Main executor: DelayableExecutor,
     private val mediaManager: MediaDataManager,
     configurationController: ConfigurationController,
-    falsingCollector: FalsingCollector,
     falsingManager: FalsingManager,
     dumpManager: DumpManager,
     private val logger: MediaUiEventLogger,
@@ -122,6 +125,7 @@
 
     /** Is the player currently visible (at the end of the transformation */
     private var playersVisible: Boolean = false
+
     /**
      * The desired location where we'll be at the end of the transformation. Usually this matches
      * the end location, except when we're still waiting on a state update call.
@@ -152,6 +156,7 @@
     @VisibleForTesting var mediaCarousel: MediaScrollView
     val mediaCarouselScrollHandler: MediaCarouselScrollHandler
     val mediaFrame: ViewGroup
+
     @VisibleForTesting
     lateinit var settingsButton: View
         private set
@@ -280,7 +285,6 @@
                 this::updatePageIndicatorLocation,
                 this::updateSeekbarListening,
                 this::closeGuts,
-                falsingCollector,
                 falsingManager,
                 this::logSmartspaceImpression,
                 logger
@@ -327,23 +331,18 @@
                     if (addOrUpdatePlayer(key, oldKey, data, isSsReactivated)) {
                         // Log card received if a new resumable media card is added
                         MediaPlayerData.getMediaPlayer(key)?.let {
-                            /* ktlint-disable max-line-length */
                             logSmartspaceCardReported(
                                 759, // SMARTSPACE_CARD_RECEIVED
                                 it.mSmartspaceId,
                                 it.mUid,
                                 surfaces =
                                     intArrayOf(
-                                        SysUiStatsLog
-                                            .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
-                                        SysUiStatsLog
-                                            .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
-                                        SysUiStatsLog
-                                            .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+                                        SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+                                        SSPACE_CARD_REPORTED__LOCKSCREEN,
+                                        SSPACE_CARD_REPORTED__DREAM_OVERLAY,
                                     ),
                                 rank = MediaPlayerData.getMediaPlayerIndex(key)
                             )
-                            /* ktlint-disable max-line-length */
                         }
                         if (
                             mediaCarouselScrollHandler.visibleToUser &&
@@ -362,24 +361,20 @@
                                         it.mUid + systemClock.currentTimeMillis().toInt()
                                     )
                                 it.mIsImpressed = false
-                                /* ktlint-disable max-line-length */
+
                                 logSmartspaceCardReported(
                                     759, // SMARTSPACE_CARD_RECEIVED
                                     it.mSmartspaceId,
                                     it.mUid,
                                     surfaces =
                                         intArrayOf(
-                                            SysUiStatsLog
-                                                .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
-                                            SysUiStatsLog
-                                                .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
-                                            SysUiStatsLog
-                                                .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+                                            SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+                                            SSPACE_CARD_REPORTED__LOCKSCREEN,
+                                            SSPACE_CARD_REPORTED__DREAM_OVERLAY,
                                         ),
                                     rank = index,
                                     receivedLatencyMillis = receivedSmartspaceCardLatency
                                 )
-                                /* ktlint-disable max-line-length */
                             }
                         }
                         // If media container area already visible to the user, log impression for
@@ -431,19 +426,16 @@
                                             it.mUid + systemClock.currentTimeMillis().toInt()
                                         )
                                     it.mIsImpressed = false
-                                    /* ktlint-disable max-line-length */
+
                                     logSmartspaceCardReported(
                                         759, // SMARTSPACE_CARD_RECEIVED
                                         it.mSmartspaceId,
                                         it.mUid,
                                         surfaces =
                                             intArrayOf(
-                                                SysUiStatsLog
-                                                    .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
-                                                SysUiStatsLog
-                                                    .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
-                                                SysUiStatsLog
-                                                    .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+                                                SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+                                                SSPACE_CARD_REPORTED__LOCKSCREEN,
+                                                SSPACE_CARD_REPORTED__DREAM_OVERLAY,
                                             ),
                                         rank = index,
                                         receivedLatencyMillis =
@@ -451,25 +443,20 @@
                                                     data.headphoneConnectionTimeMillis)
                                                 .toInt()
                                     )
-                                    /* ktlint-disable max-line-length */
                                 }
                             }
                         }
                         addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
                         MediaPlayerData.getMediaPlayer(key)?.let {
-                            /* ktlint-disable max-line-length */
                             logSmartspaceCardReported(
                                 759, // SMARTSPACE_CARD_RECEIVED
                                 it.mSmartspaceId,
                                 it.mUid,
                                 surfaces =
                                     intArrayOf(
-                                        SysUiStatsLog
-                                            .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
-                                        SysUiStatsLog
-                                            .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
-                                        SysUiStatsLog
-                                            .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+                                        SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+                                        SSPACE_CARD_REPORTED__LOCKSCREEN,
+                                        SSPACE_CARD_REPORTED__DREAM_OVERLAY,
                                     ),
                                 rank = MediaPlayerData.getMediaPlayerIndex(key),
                                 receivedLatencyMillis =
@@ -477,7 +464,6 @@
                                             data.headphoneConnectionTimeMillis)
                                         .toInt()
                             )
-                            /* ktlint-disable max-line-length */
                         }
                         if (
                             mediaCarouselScrollHandler.visibleToUser &&
@@ -560,7 +546,10 @@
         mediaCarouselScrollHandler.onSettingsButtonUpdated(settings)
         settingsButton.setOnClickListener {
             logger.logCarouselSettings()
-            activityStarter.startActivity(settingsIntent, true /* dismissShade */)
+            activityStarter.startActivity(
+                settingsIntent,
+                /* dismissShade= */ true,
+            )
         }
     }
 
@@ -1108,7 +1097,6 @@
         }
     }
 
-    @JvmOverloads
     /**
      * Log Smartspace events
      *
@@ -1127,6 +1115,7 @@
      *   between headphone connection to sysUI displays media recommendation card
      * @param isSwipeToDismiss whether is to log swipe-to-dismiss event
      */
+    @JvmOverloads
     fun logSmartspaceCardReported(
         eventId: Int,
         instanceId: Int,
@@ -1154,21 +1143,24 @@
 
         val cardinality = mediaContent.getChildCount()
         surfaces.forEach { surface ->
-            /* ktlint-disable max-line-length */
             SysUiStatsLog.write(
-                SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
+                SMARTSPACE_CARD_REPORTED,
                 eventId,
                 instanceId,
                 // Deprecated, replaced with AiAi feature type so we don't need to create logging
                 // card type for each new feature.
-                SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
+                SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
                 surface,
                 // Use -1 as rank value to indicate user swipe to dismiss the card
                 if (isSwipeToDismiss) -1 else rank,
                 cardinality,
-                if (mediaControlKey.isSsMediaRec) 15 // MEDIA_RECOMMENDATION
-                else if (mediaControlKey.isSsReactivated) 43 // MEDIA_RESUME_SS_ACTIVATED
-                else 31, // MEDIA_RESUME
+                if (mediaControlKey.isSsMediaRec) {
+                    15 // MEDIA_RECOMMENDATION
+                } else if (mediaControlKey.isSsReactivated) {
+                    43 // MEDIA_RESUME_SS_ACTIVATED
+                } else {
+                    31
+                }, // MEDIA_RESUME
                 uid,
                 interactedSubcardRank,
                 interactedSubcardCardinality,
@@ -1176,7 +1168,7 @@
                 null, // Media cards cannot have subcards.
                 null // Media cards don't have dimensions today.
             )
-            /* ktlint-disable max-line-length */
+
             if (DEBUG) {
                 Log.d(
                     TAG,
@@ -1259,6 +1251,7 @@
             instanceId = InstanceId.fakeInstanceId(-1),
             appUid = -1
         )
+
     // Whether should prioritize Smartspace card.
     internal var shouldPrioritizeSs: Boolean = false
         private set
@@ -1291,6 +1284,7 @@
 
     private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator)
     private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf()
+
     // A map that tracks order of visible media players before they get reordered.
     private val visibleMediaPlayers = LinkedHashMap<String, MediaSortKey>()
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
index ce50a11..ec0c40e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
@@ -26,11 +26,11 @@
 import androidx.core.view.GestureDetectorCompat
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringForce
+import com.android.internal.annotations.VisibleForTesting
 import com.android.settingslib.Utils
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS
-import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.PageIndicator
@@ -59,7 +59,6 @@
     private var translationChangedListener: () -> Unit,
     private var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit,
     private val closeGuts: (immediate: Boolean) -> Unit,
-    private val falsingCollector: FalsingCollector,
     private val falsingManager: FalsingManager,
     private val logSmartspaceImpression: (Boolean) -> Unit,
     private val logger: MediaUiEventLogger
@@ -67,8 +66,10 @@
     /** Is the view in RTL */
     val isRtl: Boolean
         get() = scrollView.isLayoutRtl
+
     /** Do we need falsing protection? */
     var falsingProtectionNeeded: Boolean = false
+
     /** The width of the carousel */
     private var carouselWidth: Int = 0
 
@@ -80,6 +81,7 @@
 
     /** The content where the players are added */
     private var mediaContent: ViewGroup
+
     /** The gesture detector to detect touch gestures */
     private val gestureDetector: GestureDetectorCompat
 
@@ -140,15 +142,13 @@
             ) = onScroll(down!!, lastMotion, distanceX)
 
             override fun onDown(e: MotionEvent): Boolean {
-                if (falsingProtectionNeeded) {
-                    falsingCollector.onNotificationStartDismissing()
-                }
                 return false
             }
         }
 
     /** The touch listener for the scroll view */
-    private val touchListener =
+    @VisibleForTesting
+    val touchListener =
         object : Gefingerpoken {
             override fun onTouchEvent(motionEvent: MotionEvent?) = onTouch(motionEvent!!)
             override fun onInterceptTouchEvent(ev: MotionEvent?) = onInterceptTouch(ev!!)
@@ -263,9 +263,6 @@
 
     private fun onTouch(motionEvent: MotionEvent): Boolean {
         val isUp = motionEvent.action == MotionEvent.ACTION_UP
-        if (isUp && falsingProtectionNeeded) {
-            falsingCollector.onNotificationStopDismissing()
-        }
         if (gestureDetector.onTouchEvent(motionEvent)) {
             if (isUp) {
                 // If this is an up and we're flinging, we don't want to have this touch reach
@@ -284,15 +281,14 @@
         } else if (isUp || motionEvent.action == MotionEvent.ACTION_CANCEL) {
             // It's an up and the fling didn't take it above
             val relativePos = scrollView.relativeScrollX % playerWidthPlusPadding
-            val scrollXAmount: Int
-            if (relativePos > playerWidthPlusPadding / 2) {
-                scrollXAmount = playerWidthPlusPadding - relativePos
-            } else {
-                scrollXAmount = -1 * relativePos
-            }
+            val scrollXAmount: Int =
+                if (isRtl xor (relativePos > playerWidthPlusPadding / 2)) {
+                    playerWidthPlusPadding - relativePos
+                } else {
+                    -1 * relativePos
+                }
             if (scrollXAmount != 0) {
-                val dx = if (isRtl) -scrollXAmount else scrollXAmount
-                val newScrollX = scrollView.relativeScrollX + dx
+                val newScrollX = scrollView.relativeScrollX + scrollXAmount
                 // Delay the scrolling since scrollView calls springback which cancels
                 // the animation again..
                 mainExecutor.execute { scrollView.smoothScrollTo(newScrollX, scrollView.scrollY) }
@@ -482,8 +478,11 @@
         }
         val relativeLocation =
             visibleMediaIndex.toFloat() +
-                if (playerWidthPlusPadding > 0) scrollInAmount.toFloat() / playerWidthPlusPadding
-                else 0f
+                if (playerWidthPlusPadding > 0) {
+                    scrollInAmount.toFloat() / playerWidthPlusPadding
+                } else {
+                    0f
+                }
         // Fix the location, because PageIndicator does not handle RTL internally
         val location =
             if (isRtl) {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
index 64de9bd..5d732fb 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -35,8 +35,8 @@
 import javax.inject.Inject
 
 /**
- * Controller that handles view of the recent apps selector in the media projection activity.
- * It is responsible for creating and updating recent apps view.
+ * Controller that handles view of the recent apps selector in the media projection activity. It is
+ * responsible for creating and updating recent apps view.
  */
 @MediaProjectionAppSelectorScope
 class MediaProjectionRecentsViewController
@@ -51,15 +51,21 @@
     private var views: Views? = null
     private var lastBoundData: List<RecentTask>? = null
 
+    val hasRecentTasks: Boolean
+        get() = lastBoundData?.isNotEmpty() ?: false
+
     init {
         taskViewSizeProvider.addCallback(this)
     }
 
     fun createView(parent: ViewGroup): ViewGroup =
-        views?.root ?: createRecentViews(parent).also {
-            views = it
-            lastBoundData?.let { recents -> bind(recents) }
-        }.root
+        views?.root
+            ?: createRecentViews(parent)
+                .also {
+                    views = it
+                    lastBoundData?.let { recents -> bind(recents) }
+                }
+                .root
 
     fun bind(recentTasks: List<RecentTask>) {
         views?.apply {
@@ -88,7 +94,8 @@
                 .inflate(R.layout.media_projection_recent_tasks, parent, /* attachToRoot= */ false)
                 as ViewGroup
 
-        val container = recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_container)
+        val container =
+            recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_container)
         container.setTaskHeightSize()
 
         val progress = recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_loader)
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 8d3b745..1d820a1 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -70,6 +70,7 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.preference.PreferenceManager;
@@ -85,9 +86,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
+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.dump.DumpManager;
 import com.android.systemui.people.NotificationHelper;
 import com.android.systemui.people.PeopleBackupFollowUpJob;
 import com.android.systemui.people.PeopleSpaceUtils;
@@ -99,6 +102,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.wm.shell.bubbles.Bubbles;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -119,7 +123,8 @@
 
 /** Manager for People Space widget. */
 @SysUISingleton
-public class PeopleSpaceWidgetManager {
+public class PeopleSpaceWidgetManager implements Dumpable {
+
     private static final String TAG = "PeopleSpaceWidgetMgr";
     private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
 
@@ -160,7 +165,8 @@
             CommonNotifCollection notifCollection,
             PackageManager packageManager, Optional<Bubbles> bubblesOptional,
             UserManager userManager, NotificationManager notificationManager,
-            BroadcastDispatcher broadcastDispatcher, @Background Executor bgExecutor) {
+            BroadcastDispatcher broadcastDispatcher, @Background Executor bgExecutor,
+            DumpManager dumpManager) {
         if (DEBUG) Log.d(TAG, "constructor");
         mContext = context;
         mAppWidgetManager = AppWidgetManager.getInstance(context);
@@ -180,6 +186,7 @@
         mManager = this;
         mBroadcastDispatcher = broadcastDispatcher;
         mBgExecutor = bgExecutor;
+        dumpManager.registerNormalDumpable(TAG, this);
     }
 
     /** Initializes {@PeopleSpaceWidgetManager}. */
@@ -1364,4 +1371,40 @@
                 .filter(id -> !TextUtils.isEmpty(id))
                 .collect(Collectors.toSet());
     }
+
+    @Override
+    public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+        Trace.traceBegin(Trace.TRACE_TAG_APP, TAG + ".dump");
+        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        Map<String, ?> all = sp.getAll();
+        pw.println("People widget list:");
+        for (Map.Entry<String, ?> entry : all.entrySet()) {
+            String key = entry.getKey();
+            PeopleBackupHelper.SharedFileEntryType keyType = getEntryType(entry);
+            switch (keyType) {
+                case WIDGET_ID:
+                    SharedPreferences widgetSp = mContext.getSharedPreferences(key,
+                            Context.MODE_PRIVATE);
+                    pw.print("People widget (valid) [");
+                    pw.print(key);
+                    pw.print("] shortcut id: \"");
+                    pw.print(widgetSp.getString(SHORTCUT_ID, EMPTY_STRING));
+                    pw.print("\", user id: ");
+                    pw.print(widgetSp.getInt(USER_ID, INVALID_USER_ID));
+                    pw.print(", package: ");
+                    pw.println(widgetSp.getString(PACKAGE_NAME, EMPTY_STRING));
+                    break;
+                case PEOPLE_TILE_KEY:
+                case CONTACT_URI:
+                    pw.print("Extra data [");
+                    pw.print(key);
+                    pw.print(" : ");
+                    pw.print((Set<String>) entry.getValue());
+                    pw.println("]");
+                    break;
+            }
+        }
+
+        Trace.traceEnd(Trace.TRACE_TAG_APP);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 5a1ad96..e1e1aae 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -35,11 +35,14 @@
 import android.os.Temperature;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Slog;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.Estimate;
@@ -51,17 +54,13 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.Optional;
 import java.util.concurrent.Future;
 
 import javax.inject.Inject;
 
-import dagger.Lazy;
-
 @SysUISingleton
 public class PowerUI implements CoreStartable, CommandQueue.Callbacks {
 
@@ -107,12 +106,15 @@
     @VisibleForTesting int mBatteryLevel = 100;
     @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
 
+    private boolean mInVrMode;
+
     private IThermalEventListener mSkinThermalEventListener;
     private IThermalEventListener mUsbThermalEventListener;
     private final Context mContext;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final CommandQueue mCommandQueue;
-    private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
+    @Nullable
+    private final IVrManager mVrManager;
     private final WakefulnessLifecycle.Observer mWakefulnessObserver =
             new WakefulnessLifecycle.Observer() {
                 @Override
@@ -134,17 +136,28 @@
                 }
             };
 
+    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+        @Override
+        public void onVrStateChanged(boolean enabled) {
+            mInVrMode = enabled;
+        }
+    };
+
     @Inject
-    public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
-            CommandQueue commandQueue, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
-            WarningsUI warningsUI, EnhancedEstimates enhancedEstimates,
+    public PowerUI(
+            Context context,
+            BroadcastDispatcher broadcastDispatcher,
+            CommandQueue commandQueue,
+            @Nullable IVrManager vrManager,
+            WarningsUI warningsUI,
+            EnhancedEstimates enhancedEstimates,
             WakefulnessLifecycle wakefulnessLifecycle,
             PowerManager powerManager,
             UserTracker userTracker) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
-        mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
+        mVrManager = vrManager;
         mWarnings = warningsUI;
         mEnhancedEstimates = enhancedEstimates;
         mPowerManager = powerManager;
@@ -164,7 +177,7 @@
         };
         final ContentResolver resolver = mContext.getContentResolver();
         resolver.registerContentObserver(Settings.Global.getUriFor(
-                Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
+                        Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
                 false, obs, UserHandle.USER_ALL);
         updateBatteryWarningLevels();
         mReceiver.init();
@@ -199,6 +212,14 @@
                 });
         initThermalEventListeners();
         mCommandQueue.addCallback(this);
+
+        if (mVrManager != null) {
+            try {
+                mVrManager.registerListener(mVrStateCallbacks);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
+            }
+        }
     }
 
     @Override
@@ -718,10 +739,7 @@
             int status = temp.getStatus();
 
             if (status >= Temperature.THROTTLING_EMERGENCY) {
-                final Optional<CentralSurfaces> centralSurfacesOptional =
-                        mCentralSurfacesOptionalLazy.get();
-                if (!centralSurfacesOptional.map(CentralSurfaces::isDeviceInVrMode)
-                        .orElse(false)) {
+                if (!mInVrMode) {
                     mWarnings.showHighTemperatureWarning();
                     Slog.d(TAG, "SkinThermalEventListener: notifyThrottling was called "
                             + ", current skin status = " + status
diff --git a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
index 69cb611..b2a8719 100644
--- a/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepository.kt
@@ -39,6 +39,9 @@
 
     /** Wakes up the device. */
     fun wakeUp(why: String, @PowerManager.WakeReason wakeReason: Int)
+
+    /** Notifies the power repository that a user touch happened. */
+    fun userTouch()
 }
 
 @SysUISingleton
@@ -83,6 +86,14 @@
         )
     }
 
+    override fun userTouch() {
+        manager.userActivity(
+            systemClock.uptimeMillis(),
+            PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+            /* flags= */ 0,
+        )
+    }
+
     companion object {
         private const val TAG = "PowerRepository"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
index 809edc0..16885ed 100644
--- a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
@@ -19,6 +19,7 @@
 
 import android.os.PowerManager
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorActual
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -34,7 +35,7 @@
 constructor(
     private val repository: PowerRepository,
     private val keyguardRepository: KeyguardRepository,
-    private val falsingCollector: FalsingCollector,
+    @FalsingCollectorActual private val falsingCollector: FalsingCollector,
     private val screenOffAnimationController: ScreenOffAnimationController,
     private val statusBarStateController: StatusBarStateController,
 ) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index d2eac45..37e750b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -235,11 +235,15 @@
                 quickStatusBarHeaderController.setContentMargins(mContentHorizontalPadding,
                         mContentHorizontalPadding);
             } else {
-                view.setPaddingRelative(
-                        mContentHorizontalPadding,
-                        view.getPaddingTop(),
-                        mContentHorizontalPadding,
-                        view.getPaddingBottom());
+                // Set the horizontal paddings unless the view is the Compose implementation of the
+                // footer actions.
+                if (view.getTag(R.id.tag_compose_qs_footer_actions) == null) {
+                    view.setPaddingRelative(
+                            mContentHorizontalPadding,
+                            view.getPaddingTop(),
+                            mContentHorizontalPadding,
+                            view.getPaddingBottom());
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index d801faa..596d024 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -303,6 +303,17 @@
         // to all views except for qs_footer_actions, so we set it to the Compose view.
         composeView.setId(R.id.qs_footer_actions);
 
+        // Set this tag so that QSContainerImpl does not add horizontal paddings to this Compose
+        // implementation of the footer actions. They will be set in Compose instead so that the
+        // background fills the full screen width.
+        composeView.setTag(R.id.tag_compose_qs_footer_actions, true);
+
+        // Set the same elevation as the View implementation, otherwise the footer actions will be
+        // drawn below the scroll view with QS grid and clicks won't get through on small devices
+        // where there isn't enough vertical space to show all the tiles and the footer actions.
+        composeView.setElevation(
+                composeView.getContext().getResources().getDimension(R.dimen.qs_panel_elevation));
+
         // Replace the View by the Compose provided one.
         ViewGroup parent = (ViewGroup) footerActionsView.getParent();
         ViewGroup.LayoutParams layoutParams = footerActionsView.getLayoutParams();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
index 86ef7ef..66f020f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
@@ -10,7 +10,9 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
-    },
+    }
+  ],
+ "postsubmit": [
     {
       "name": "QuickSettingsDeviceResetTests",
       "options": [
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 54376fe..e9a2428 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -18,6 +18,8 @@
 
 import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
 
+import static com.android.systemui.flags.Flags.SIGNAL_CALLBACK_DEPRECATION;
+
 import android.annotation.NonNull;
 import android.app.Dialog;
 import android.content.Intent;
@@ -42,6 +44,7 @@
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -54,6 +57,8 @@
 import com.android.systemui.statusbar.connectivity.SignalCallback;
 import com.android.systemui.statusbar.connectivity.WifiIndicators;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor;
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -61,6 +66,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 
 import javax.inject.Inject;
 
@@ -79,6 +85,9 @@
     private final NetworkController mNetworkController;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
     private final Callback mCallback = new Callback();
+    private final WifiInteractor mWifiInteractor;
+    private final TileJavaAdapter mJavaAdapter;
+    private final FeatureFlags mFeatureFlags;
     private boolean mWifiConnected;
     private boolean mHotspotConnected;
 
@@ -97,7 +106,10 @@
             KeyguardStateController keyguardStateController,
             NetworkController networkController,
             HotspotController hotspotController,
-            DialogLaunchAnimator dialogLaunchAnimator
+            DialogLaunchAnimator dialogLaunchAnimator,
+            WifiInteractor wifiInteractor,
+            TileJavaAdapter javaAdapter,
+            FeatureFlags featureFlags
     ) {
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
@@ -105,9 +117,16 @@
         mKeyguard = keyguardStateController;
         mNetworkController = networkController;
         mDialogLaunchAnimator = dialogLaunchAnimator;
+        mWifiInteractor = wifiInteractor;
+        mJavaAdapter = javaAdapter;
+        mFeatureFlags = featureFlags;
         mController.observe(this, mCallback);
         mKeyguard.observe(this, mCallback);
-        mNetworkController.observe(this, mSignalCallback);
+        if (!mFeatureFlags.isEnabled(SIGNAL_CALLBACK_DEPRECATION)) {
+            mNetworkController.observe(this, mSignalCallback);
+        } else {
+            mJavaAdapter.bind(this, mWifiInteractor.getWifiNetwork(), mNetworkModelConsumer);
+        }
         hotspotController.observe(this, mHotspotCallback);
     }
 
@@ -293,19 +312,37 @@
         return mWifiConnected || mHotspotConnected;
     }
 
+    private void setWifiConnected(boolean connected) {
+        if (connected != mWifiConnected) {
+            mWifiConnected = connected;
+            // Hotspot is not connected, so changes here should update
+            if (!mHotspotConnected) {
+                refreshState();
+            }
+        }
+    }
+
+    private void setHotspotConnected(boolean connected) {
+        if (connected != mHotspotConnected) {
+            mHotspotConnected = connected;
+            // Wifi is not connected, so changes here should update
+            if (!mWifiConnected) {
+                refreshState();
+            }
+        }
+    }
+
+    private final Consumer<WifiNetworkModel> mNetworkModelConsumer = (model) -> {
+        setWifiConnected(model instanceof WifiNetworkModel.Active);
+    };
+
     private final SignalCallback mSignalCallback = new SignalCallback() {
                 @Override
                 public void setWifiIndicators(@NonNull WifiIndicators indicators) {
                     // statusIcon.visible has the connected status information
                     boolean enabledAndConnected = indicators.enabled
-                            && (indicators.qsIcon == null ? false : indicators.qsIcon.visible);
-                    if (enabledAndConnected != mWifiConnected) {
-                        mWifiConnected = enabledAndConnected;
-                        // Hotspot is not connected, so changes here should update
-                        if (!mHotspotConnected) {
-                            refreshState();
-                        }
-                    }
+                            && (indicators.qsIcon != null && indicators.qsIcon.visible);
+                    setWifiConnected(enabledAndConnected);
                 }
             };
 
@@ -314,13 +351,7 @@
                 @Override
                 public void onHotspotChanged(boolean enabled, int numDevices) {
                     boolean enabledAndConnected = enabled && numDevices > 0;
-                    if (enabledAndConnected != mHotspotConnected) {
-                        mHotspotConnected = enabledAndConnected;
-                        // Wifi is not connected, so changes here should update
-                        if (!mWifiConnected) {
-                            refreshState();
-                        }
-                    }
+                    setHotspotConnected(enabledAndConnected);
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
new file mode 100644
index 0000000..3b2f8b7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles
+
+import android.content.Context
+import android.content.Intent
+import android.os.Handler
+import android.os.Looper
+import android.provider.Settings
+import android.view.View
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.qs.QSIconView
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.AlphaControlledSignalTileView
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tiles.dialog.InternetDialogFactory
+import com.android.systemui.statusbar.connectivity.AccessPointController
+import com.android.systemui.statusbar.pipeline.shared.ui.binder.InternetTileBinder
+import com.android.systemui.statusbar.pipeline.shared.ui.model.InternetTileModel
+import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.InternetTileViewModel
+import javax.inject.Inject
+
+class InternetTileNewImpl
+@Inject
+constructor(
+    host: QSHost,
+    uiEventLogger: QsEventLogger,
+    @Background backgroundLooper: Looper,
+    @Main private val mainHandler: Handler,
+    falsingManager: FalsingManager,
+    metricsLogger: MetricsLogger,
+    statusBarStateController: StatusBarStateController,
+    activityStarter: ActivityStarter,
+    qsLogger: QSLogger,
+    viewModel: InternetTileViewModel,
+    private val internetDialogFactory: InternetDialogFactory,
+    private val accessPointController: AccessPointController,
+) :
+    QSTileImpl<QSTile.SignalState>(
+        host,
+        uiEventLogger,
+        backgroundLooper,
+        mainHandler,
+        falsingManager,
+        metricsLogger,
+        statusBarStateController,
+        activityStarter,
+        qsLogger
+    ) {
+    private var model: InternetTileModel = viewModel.tileModel.value
+
+    init {
+        InternetTileBinder.bind(lifecycle, viewModel.tileModel) { newModel ->
+            model = newModel
+            refreshState()
+        }
+    }
+
+    override fun createTileView(context: Context): QSIconView =
+        AlphaControlledSignalTileView(context)
+
+    override fun getTileLabel(): CharSequence =
+        mContext.getString(R.string.quick_settings_internet_label)
+
+    override fun newTileState(): QSTile.SignalState {
+        return QSTile.SignalState().also { it.forceExpandIcon = true }
+    }
+
+    override fun handleClick(view: View?) {
+        mainHandler.post {
+            internetDialogFactory.create(
+                aboveStatusBar = true,
+                accessPointController.canConfigMobileData(),
+                accessPointController.canConfigWifi(),
+                view,
+            )
+        }
+    }
+
+    override fun handleUpdateState(state: QSTile.SignalState, arg: Any?) {
+        state.label = mContext.resources.getString(R.string.quick_settings_internet_label)
+
+        model.applyTo(state, mContext)
+    }
+
+    override fun getLongClickIntent(): Intent = WIFI_SETTINGS
+
+    companion object {
+        private val WIFI_SETTINGS = Intent(Settings.ACTION_WIFI_SETTINGS)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/TileJavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/TileJavaAdapter.kt
new file mode 100644
index 0000000..a2430ad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/TileJavaAdapter.kt
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (C) 2023 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package com.android.systemui.qs.tiles
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.dagger.SysUISingleton
+import java.util.function.Consumer
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+/**
+ * Utility for binding tiles to kotlin flows. Similar to [JavaAdapter] and usable for QS tiles. We
+ * use [Lifecycle.State.RESUMED] here to match the implementation of [CallbackController.observe]
+ */
+@SysUISingleton
+class TileJavaAdapter @Inject constructor() {
+    fun <T> bind(
+        lifecycleOwner: LifecycleOwner,
+        flow: Flow<T>,
+        consumer: Consumer<T>,
+    ) {
+        lifecycleOwner.lifecycleScope.launch {
+            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+                flow.collect { consumer.accept(it) }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 4c6281e..9edd2c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -18,13 +18,17 @@
 
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import javax.inject.Inject
 
 /** Models UI state and handles user input for the quick settings scene. */
 @SysUISingleton
 class QuickSettingsSceneViewModel
 @Inject
-constructor(private val bouncerInteractor: BouncerInteractor) {
+constructor(
+    private val bouncerInteractor: BouncerInteractor,
+    val shadeHeaderViewModel: ShadeHeaderViewModel,
+) {
     /** Notifies that some content in quick settings was clicked. */
     fun onContentClicked() {
         bouncerInteractor.showOrUnlockDevice()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 3a64a6a..d23beda 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -85,7 +85,6 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.model.SysUiState;
@@ -96,6 +95,7 @@
 import com.android.systemui.navigationbar.buttons.KeyButtonView;
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeViewController;
@@ -143,6 +143,7 @@
 
     private final Context mContext;
     private final FeatureFlags mFeatureFlags;
+    private final SceneContainerFlags mSceneContainerFlags;
     private final Executor mMainExecutor;
     private final ShellInterface mShellInterface;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -218,7 +219,7 @@
 
                             // If scene framework is enabled, set the scene container window to
                             // visible and let the touch "slip" into that window.
-                            if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+                            if (mSceneContainerFlags.isEnabled()) {
                                 mSceneInteractor.get().setVisible(true, "swipe down on launcher");
                             } else {
                                 centralSurfaces.onInputFocusTransfer(
@@ -229,7 +230,7 @@
                         if (action == ACTION_UP || action == ACTION_CANCEL) {
                             mInputFocusTransferStarted = false;
 
-                            if (!mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+                            if (!mSceneContainerFlags.isEnabled()) {
                                 float velocity = (event.getY() - mInputFocusTransferStartY)
                                         / (event.getEventTime() - mInputFocusTransferStartMillis);
                                 centralSurfaces.onInputFocusTransfer(mInputFocusTransferStarted,
@@ -582,6 +583,7 @@
             KeyguardUnlockAnimationController sysuiUnlockAnimationController,
             AssistUtils assistUtils,
             FeatureFlags featureFlags,
+            SceneContainerFlags sceneContainerFlags,
             DumpManager dumpManager,
             Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder
     ) {
@@ -592,6 +594,7 @@
 
         mContext = context;
         mFeatureFlags = featureFlags;
+        mSceneContainerFlags = sceneContainerFlags;
         mMainExecutor = mainExecutor;
         mShellInterface = shellInterface;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/src/com/android/systemui/scene/EmptySceneModule.kt
similarity index 69%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to packages/SystemUI/src/com/android/systemui/scene/EmptySceneModule.kt
index 24064b1..efb9375 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/EmptySceneModule.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,19 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.ui.composable
+package com.android.systemui.scene
 
 import com.android.systemui.scene.shared.model.Scene
 import dagger.Module
-import dagger.multibindings.Multibinds
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
 
 @Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+object EmptySceneModule {
+
+    @Provides
+    @ElementsIntoSet
+    fun emptySceneSet(): Set<Scene> {
+        return emptySet()
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
new file mode 100644
index 0000000..fcbe9a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene
+
+import com.android.systemui.scene.shared.flag.SceneContainerFlagsModule
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneKey
+import dagger.Module
+import dagger.Provides
+
+/** Scene framework Dagger module suitable for variants that want to exclude "keyguard" scenes. */
+@Module(
+    includes =
+        [
+            EmptySceneModule::class,
+            GoneSceneModule::class,
+            QuickSettingsSceneModule::class,
+            SceneContainerFlagsModule::class,
+            ShadeSceneModule::class,
+        ],
+)
+object KeyguardlessSceneContainerFrameworkModule {
+
+    // TODO(b/298234162): provide a SceneContainerStartable without lockscreen and bouncer.
+
+    @Provides
+    fun containerConfig(): SceneContainerConfig {
+        return SceneContainerConfig(
+            // Note that this list is in z-order. The first one is the bottom-most and the
+            // last one is top-most.
+            sceneKeys =
+                listOf(
+                    SceneKey.Gone,
+                    SceneKey.Shade,
+                    SceneKey.QuickSettings,
+                ),
+            initialSceneKey = SceneKey.Gone,
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 7147951..b36ec32 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -16,19 +16,62 @@
 
 package com.android.systemui.scene
 
-import com.android.systemui.keyguard.ui.view.LockscreenSceneModule
-import com.android.systemui.scene.domain.startable.SceneContainerStartableModule
-import com.android.systemui.scene.shared.model.SceneContainerConfigModule
-import com.android.systemui.scene.ui.composable.SceneModule
+import com.android.systemui.CoreStartable
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.scene.domain.startable.SceneContainerStartable
+import com.android.systemui.scene.shared.flag.SceneContainerFlagsModule
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneKey
+import dagger.Binds
 import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
 
+/** Scene framework Dagger module suitable for AOSP. */
 @Module(
     includes =
         [
+            BouncerSceneModule::class,
+            EmptySceneModule::class,
+            GoneSceneModule::class,
             LockscreenSceneModule::class,
-            SceneContainerConfigModule::class,
-            SceneContainerStartableModule::class,
-            SceneModule::class,
+            QuickSettingsSceneModule::class,
+            SceneContainerFlagsModule::class,
+            ShadeSceneModule::class,
         ],
 )
-object SceneContainerFrameworkModule
+interface SceneContainerFrameworkModule {
+
+    @Binds
+    @IntoMap
+    @ClassKey(SceneContainerStartable::class)
+    fun containerStartable(impl: SceneContainerStartable): CoreStartable
+
+    @Binds
+    @IntoMap
+    @ClassKey(WindowRootViewVisibilityInteractor::class)
+    fun bindWindowRootViewVisibilityInteractor(
+        impl: WindowRootViewVisibilityInteractor
+    ): CoreStartable
+
+    companion object {
+
+        @Provides
+        fun containerConfig(): SceneContainerConfig {
+            return SceneContainerConfig(
+                // Note that this list is in z-order. The first one is the bottom-most and the
+                // last one is top-most.
+                sceneKeys =
+                    listOf(
+                        SceneKey.Gone,
+                        SceneKey.Lockscreen,
+                        SceneKey.Bouncer,
+                        SceneKey.Shade,
+                        SceneKey.QuickSettings,
+                    ),
+                initialSceneKey = SceneKey.Lockscreen,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
new file mode 100644
index 0000000..c10e51b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/ShadelessSceneContainerFrameworkModule.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene
+
+import com.android.systemui.scene.shared.flag.SceneContainerFlagsModule
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneKey
+import dagger.Module
+import dagger.Provides
+
+/** Scene framework Dagger module suitable for variants that want to exclude "shade" scenes. */
+@Module(
+    includes =
+        [
+            BouncerSceneModule::class,
+            EmptySceneModule::class,
+            GoneSceneModule::class,
+            LockscreenSceneModule::class,
+            SceneContainerFlagsModule::class,
+        ],
+)
+object ShadelessSceneContainerFrameworkModule {
+
+    // TODO(b/298229861): provide a version of SceneContainerStartable without shade and qs.
+
+    @Provides
+    fun containerConfig(): SceneContainerConfig {
+        return SceneContainerConfig(
+            // Note that this list is in z-order. The first one is the bottom-most and the
+            // last one is top-most.
+            sceneKeys =
+                listOf(
+                    SceneKey.Gone,
+                    SceneKey.Lockscreen,
+                    SceneKey.Bouncer,
+                ),
+            initialSceneKey = SceneKey.Lockscreen,
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepository.kt
new file mode 100644
index 0000000..d833e56
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepository.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.data.repository
+
+import android.os.RemoteException
+import com.android.internal.statusbar.IStatusBarService
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.UiBackground
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** Source of truth for the visibility of various parts of the window root view. */
+@SysUISingleton
+class WindowRootViewVisibilityRepository
+@Inject
+constructor(
+    private val statusBarService: IStatusBarService,
+    @UiBackground private val uiBgExecutor: Executor,
+) {
+    private val _isLockscreenOrShadeVisible = MutableStateFlow(false)
+    val isLockscreenOrShadeVisible: StateFlow<Boolean> = _isLockscreenOrShadeVisible.asStateFlow()
+
+    fun setIsLockscreenOrShadeVisible(visible: Boolean) {
+        _isLockscreenOrShadeVisible.value = visible
+    }
+
+    /**
+     * Called when the lockscreen or shade has been shown and can be interacted with so that SysUI
+     * can notify external services.
+     */
+    fun onLockscreenOrShadeInteractive(
+        shouldClearNotificationEffects: Boolean,
+        notificationCount: Int,
+    ) {
+        executeServiceCallOnUiBg {
+            statusBarService.onPanelRevealed(shouldClearNotificationEffects, notificationCount)
+        }
+    }
+
+    /**
+     * Called when the lockscreen or shade no longer can be interactecd with so that SysUI can
+     * notify external services.
+     */
+    fun onLockscreenOrShadeNotInteractive() {
+        executeServiceCallOnUiBg { statusBarService.onPanelHidden() }
+    }
+
+    private fun executeServiceCallOnUiBg(runnable: () -> Unit) {
+        uiBgExecutor.execute {
+            try {
+                runnable.invoke()
+            } catch (ex: RemoteException) {
+                // Won't fail unless the world has ended
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index a7434c6..7353379 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.power.data.repository.PowerRepository
 import com.android.systemui.scene.data.repository.SceneContainerRepository
 import com.android.systemui.scene.shared.logger.SceneLogger
 import com.android.systemui.scene.shared.model.ObservableTransitionState
@@ -42,8 +43,9 @@
 class SceneInteractor
 @Inject
 constructor(
-    @Application applicationScope: CoroutineScope,
+    @Application private val applicationScope: CoroutineScope,
     private val repository: SceneContainerRepository,
+    private val powerRepository: PowerRepository,
     private val logger: SceneLogger,
 ) {
 
@@ -144,6 +146,28 @@
         return repository.setVisible(isVisible)
     }
 
+    /** True if there is a transition happening from and to the specified scenes. */
+    fun transitioning(from: SceneKey, to: SceneKey): StateFlow<Boolean> {
+        fun transitioning(
+            state: ObservableTransitionState,
+            from: SceneKey,
+            to: SceneKey,
+        ): Boolean {
+            return (state as? ObservableTransitionState.Transition)?.let {
+                it.fromScene == from && it.toScene == to
+            }
+                ?: false
+        }
+
+        return transitionState
+            .map { state -> transitioning(state, from, to) }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = transitioning(transitionState.value, from, to),
+            )
+    }
+
     /**
      * Binds the given flow so the system remembers it.
      *
@@ -153,6 +177,11 @@
         repository.setTransitionState(transitionState)
     }
 
+    /** Handles a user input event. */
+    fun onUserInput() {
+        powerRepository.userTouch()
+    }
+
     /**
      * Notifies that the UI has transitioned sufficiently to the given scene.
      *
@@ -161,7 +190,7 @@
      * Once a transition between one scene and another passes a threshold, the UI invokes this
      * method to report it, updating the value in [desiredScene] to match what the UI shows.
      */
-    internal fun onSceneChanged(scene: SceneModel, loggingReason: String) {
+    fun onSceneChanged(scene: SceneModel, loggingReason: String) {
         updateDesiredScene(scene, loggingReason, logger::logSceneChangeCommitted)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
new file mode 100644
index 0000000..16ffcc2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.scene.domain.interactor
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.init.NotificationsController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Business logic about the visibility of various parts of the window root view. */
+@SysUISingleton
+class WindowRootViewVisibilityInteractor
+@Inject
+constructor(
+    @Application private val scope: CoroutineScope,
+    private val windowRootViewVisibilityRepository: WindowRootViewVisibilityRepository,
+    private val keyguardRepository: KeyguardRepository,
+    private val headsUpManager: HeadsUpManager,
+) : CoreStartable {
+
+    private var notificationPresenter: NotificationPresenter? = null
+    private var notificationsController: NotificationsController? = null
+
+    private val isNotifPresenterFullyCollapsed: Boolean
+        get() = notificationPresenter?.isPresenterFullyCollapsed ?: true
+
+    /**
+     * True if lockscreen (including AOD) or the shade is visible and false otherwise. Notably,
+     * false if the bouncer is visible.
+     *
+     * TODO(b/297080059): Use [SceneInteractor] as the source of truth if the scene flag is on.
+     */
+    val isLockscreenOrShadeVisible: StateFlow<Boolean> =
+        windowRootViewVisibilityRepository.isLockscreenOrShadeVisible
+
+    /**
+     * True if lockscreen (including AOD) or the shade is visible **and** the user is currently
+     * interacting with the device, false otherwise. Notably, false if the bouncer is visible and
+     * false if the device is asleep.
+     */
+    val isLockscreenOrShadeVisibleAndInteractive: StateFlow<Boolean> =
+        combine(
+                isLockscreenOrShadeVisible,
+                keyguardRepository.wakefulness,
+            ) { isKeyguardAodOrShadeVisible, wakefulness ->
+                isKeyguardAodOrShadeVisible && wakefulness.isDeviceInteractive()
+            }
+            .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
+
+    /**
+     * Sets classes that aren't easily injectable on this class.
+     *
+     * TODO(b/277762009): Inject these directly instead.
+     */
+    fun setUp(
+        presenter: NotificationPresenter?,
+        notificationsController: NotificationsController?,
+    ) {
+        this.notificationPresenter = presenter
+        this.notificationsController = notificationsController
+    }
+
+    override fun start() {
+        scope.launch {
+            isLockscreenOrShadeVisibleAndInteractive.collect { interactive ->
+                if (interactive) {
+                    windowRootViewVisibilityRepository.onLockscreenOrShadeInteractive(
+                        getShouldClearNotificationEffects(keyguardRepository.statusBarState.value),
+                        getNotificationLoad(),
+                    )
+                } else {
+                    windowRootViewVisibilityRepository.onLockscreenOrShadeNotInteractive()
+                }
+            }
+        }
+    }
+
+    fun setIsLockscreenOrShadeVisible(visible: Boolean) {
+        windowRootViewVisibilityRepository.setIsLockscreenOrShadeVisible(visible)
+    }
+
+    private fun getShouldClearNotificationEffects(statusBarState: StatusBarState): Boolean {
+        return !isNotifPresenterFullyCollapsed &&
+            (statusBarState == StatusBarState.SHADE ||
+                statusBarState == StatusBarState.SHADE_LOCKED)
+    }
+
+    private fun getNotificationLoad(): Int {
+        return if (headsUpManager.hasPinnedHeadsUp() && isNotifPresenterFullyCollapsed) {
+            1
+        } else {
+            notificationsController?.getActiveNotificationsCount() ?: 0
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 1747099..722d366 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -14,21 +14,24 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.scene.domain.startable
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorActual
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.DisplayId
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.model.SysUiState
 import com.android.systemui.model.updateFlags
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.logger.SceneLogger
 import com.android.systemui.scene.shared.model.ObservableTransitionState
 import com.android.systemui.scene.shared.model.SceneKey
@@ -40,7 +43,12 @@
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.distinctUntilChangedBy
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.launch
@@ -57,20 +65,25 @@
     private val sceneInteractor: SceneInteractor,
     private val authenticationInteractor: AuthenticationInteractor,
     private val keyguardInteractor: KeyguardInteractor,
-    private val featureFlags: FeatureFlags,
+    private val flags: SceneContainerFlags,
     private val sysUiState: SysUiState,
     @DisplayId private val displayId: Int,
     private val sceneLogger: SceneLogger,
+    @FalsingCollectorActual private val falsingCollector: FalsingCollector,
 ) : CoreStartable {
 
     override fun start() {
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (flags.isEnabled()) {
             sceneLogger.logFrameworkEnabled(isEnabled = true)
             hydrateVisibility()
             automaticallySwitchScenes()
             hydrateSystemUiState()
+            collectFalsingSignals()
         } else {
-            sceneLogger.logFrameworkEnabled(isEnabled = false)
+            sceneLogger.logFrameworkEnabled(
+                isEnabled = false,
+                reason = flags.requirementDescription(),
+            )
         }
     }
 
@@ -225,6 +238,66 @@
         }
     }
 
+    /** Collects and reports signals into the falsing system. */
+    private fun collectFalsingSignals() {
+        applicationScope.launch {
+            authenticationInteractor.isLockscreenDismissed.collect { isLockscreenDismissed ->
+                if (isLockscreenDismissed) {
+                    falsingCollector.onSuccessfulUnlock()
+                }
+            }
+        }
+
+        applicationScope.launch {
+            keyguardInteractor.isDozing.distinctUntilChanged().collect { isDozing ->
+                falsingCollector.setShowingAod(isDozing)
+            }
+        }
+
+        applicationScope.launch {
+            keyguardInteractor.isAodAvailable
+                .flatMapLatest { isAodAvailable ->
+                    if (!isAodAvailable) {
+                        keyguardInteractor.wakefulnessModel
+                    } else {
+                        emptyFlow()
+                    }
+                }
+                .map { wakefulnessModel ->
+                    val wakeChange: Boolean? =
+                        when (wakefulnessModel.state) {
+                            WakefulnessState.STARTING_TO_WAKE -> true
+                            WakefulnessState.ASLEEP -> false
+                            else -> null
+                        }
+                    (wakeChange to wakefulnessModel.lastWakeReason).takeIf { wakeChange != null }
+                }
+                .filterNotNull()
+                .distinctUntilChangedBy { it.first }
+                .collect { (wakeChange, wakeReason) ->
+                    when {
+                        wakeChange == true && wakeReason.isTouch ->
+                            falsingCollector.onScreenOnFromTouch()
+                        wakeChange == true -> falsingCollector.onScreenTurningOn()
+                        wakeChange == false -> falsingCollector.onScreenOff()
+                    }
+                }
+        }
+
+        applicationScope.launch {
+            sceneInteractor.desiredScene
+                .map { it.key == SceneKey.Bouncer }
+                .distinctUntilChanged()
+                .collect { switchedToBouncerScene ->
+                    if (switchedToBouncerScene) {
+                        falsingCollector.onBouncerShown()
+                    } else {
+                        falsingCollector.onBouncerHidden()
+                    }
+                }
+        }
+    }
+
     private fun switchToScene(targetSceneKey: SceneKey, loggingReason: String) {
         sceneInteractor.changeScene(
             scene = SceneModel(targetSceneKey),
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
new file mode 100644
index 0000000..83fb723
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.shared.flag
+
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flag
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ReleasedFlag
+import com.android.systemui.flags.ResourceBooleanFlag
+import com.android.systemui.flags.UnreleasedFlag
+import dagger.Module
+import dagger.Provides
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/**
+ * Defines interface for classes that can check whether the scene container framework feature is
+ * enabled.
+ */
+interface SceneContainerFlags {
+
+    /** Returns `true` if the Scene Container Framework is enabled; `false` otherwise. */
+    fun isEnabled(): Boolean
+
+    /** Returns a developer-readable string that describes the current requirement list. */
+    fun requirementDescription(): String
+}
+
+class SceneContainerFlagsImpl
+@AssistedInject
+constructor(
+    private val featureFlags: FeatureFlagsClassic,
+    @Assisted private val isComposeAvailable: Boolean,
+) : SceneContainerFlags {
+
+    companion object {
+        @VisibleForTesting
+        val flags: List<Flag<Boolean>> =
+            listOf(
+                Flags.SCENE_CONTAINER,
+                Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA,
+                Flags.MIGRATE_LOCK_ICON,
+                Flags.MIGRATE_NSSL,
+                Flags.MIGRATE_KEYGUARD_STATUS_VIEW,
+            )
+    }
+
+    /** The list of requirements, all must be met for the feature to be enabled. */
+    private val requirements =
+        flags.map { FlagMustBeEnabled(it) } +
+            listOf(ComposeMustBeAvailable(), CompileTimeFlagMustBeEnabled())
+
+    override fun isEnabled(): Boolean {
+        return requirements.all { it.isMet() }
+    }
+
+    override fun requirementDescription(): String {
+        return buildString {
+            requirements.forEach { requirement ->
+                append('\n')
+                append(if (requirement.isMet()) "    [MET]" else "[NOT MET]")
+                append(" ${requirement.name}")
+            }
+        }
+    }
+
+    private interface Requirement {
+        val name: String
+
+        fun isMet(): Boolean
+    }
+
+    private inner class ComposeMustBeAvailable : Requirement {
+        override val name = "Jetpack Compose must be available"
+
+        override fun isMet(): Boolean {
+            return isComposeAvailable
+        }
+    }
+
+    private inner class CompileTimeFlagMustBeEnabled : Requirement {
+        override val name = "Flags.SCENE_CONTAINER_ENABLED must be enabled in code"
+
+        override fun isMet(): Boolean {
+            return Flags.SCENE_CONTAINER_ENABLED
+        }
+    }
+
+    private inner class FlagMustBeEnabled<FlagType : Flag<*>>(
+        private val flag: FlagType,
+    ) : Requirement {
+        override val name = "Flag ${flag.name} must be enabled"
+
+        override fun isMet(): Boolean {
+            return when (flag) {
+                is ResourceBooleanFlag -> featureFlags.isEnabled(flag)
+                is ReleasedFlag -> featureFlags.isEnabled(flag)
+                is UnreleasedFlag -> featureFlags.isEnabled(flag)
+                else -> error("Unsupported flag type ${flag.javaClass}")
+            }
+        }
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(isComposeAvailable: Boolean): SceneContainerFlagsImpl
+    }
+}
+
+@Module
+object SceneContainerFlagsModule {
+
+    @Provides
+    @SysUISingleton
+    fun impl(factory: SceneContainerFlagsImpl.Factory): SceneContainerFlags {
+        return factory.create(ComposeFacade.isComposeAvailable())
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index 62136dc..c2c2e04 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -24,16 +24,21 @@
 
 class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: LogBuffer) {
 
-    fun logFrameworkEnabled(isEnabled: Boolean) {
+    fun logFrameworkEnabled(isEnabled: Boolean, reason: String? = null) {
         fun asWord(isEnabled: Boolean): String {
             return if (isEnabled) "enabled" else "disabled"
         }
 
         logBuffer.log(
             tag = TAG,
-            level = LogLevel.INFO,
-            messageInitializer = { bool1 = isEnabled },
-            messagePrinter = { "Scene framework is ${asWord(bool1)}" }
+            level = if (isEnabled) LogLevel.INFO else LogLevel.WARNING,
+            messageInitializer = {
+                bool1 = isEnabled
+                str1 = reason
+            },
+            messagePrinter = {
+                "Scene framework is ${asWord(bool1)}${if (str1 != null) " $str1" else ""}"
+            }
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
deleted file mode 100644
index f74005b..0000000
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneContainerConfigModule.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.scene.shared.model
-
-import dagger.Module
-import dagger.Provides
-
-@Module
-object SceneContainerConfigModule {
-
-    @Provides
-    fun containerConfig(): SceneContainerConfig {
-        return SceneContainerConfig(
-            // Note that this list is in z-order. The first one is the bottom-most and the
-            // last
-            // one is top-most.
-            sceneKeys =
-                listOf(
-                    SceneKey.Gone,
-                    SceneKey.Lockscreen,
-                    SceneKey.Bouncer,
-                    SceneKey.Shade,
-                    SceneKey.QuickSettings,
-                ),
-            initialSceneKey = SceneKey.Lockscreen,
-        )
-    }
-}
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 f9324a9..3e76607 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
@@ -110,6 +110,7 @@
     //  SysUI altogether.
     private fun createVisibilityToggleView(otherView: View): View {
         val toggleView = View(otherView.context)
+        otherView.isVisible = false
         toggleView.layoutParams = FrameLayout.LayoutParams(200, 200, Gravity.CENTER_HORIZONTAL)
         toggleView.setOnClickListener {
             val now = Instant.now()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
index c9a73e6..ef688a8 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
 package com.android.systemui.scene.ui.view
 
 import android.annotation.SuppressLint
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 5c16fb5..2431660 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
@@ -16,6 +16,8 @@
 
 package com.android.systemui.scene.ui.viewmodel
 
+import android.view.MotionEvent
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.ObservableTransitionState
@@ -30,7 +32,8 @@
 class SceneContainerViewModel
 @Inject
 constructor(
-    private val interactor: SceneInteractor,
+    private val sceneInteractor: SceneInteractor,
+    private val falsingInteractor: FalsingInteractor,
 ) {
     /**
      * Keys of all scenes in the container.
@@ -38,17 +41,17 @@
      * The scenes will be sorted in z-order such that the last one is the one that should be
      * rendered on top of all previous ones.
      */
-    val allSceneKeys: List<SceneKey> = interactor.allSceneKeys()
+    val allSceneKeys: List<SceneKey> = sceneInteractor.allSceneKeys()
 
     /** The scene that should be rendered. */
-    val currentScene: StateFlow<SceneModel> = interactor.desiredScene
+    val currentScene: StateFlow<SceneModel> = sceneInteractor.desiredScene
 
     /** Whether the container is visible. */
-    val isVisible: StateFlow<Boolean> = interactor.isVisible
+    val isVisible: StateFlow<Boolean> = sceneInteractor.isVisible
 
     /** Notifies that the UI has transitioned sufficiently to the given scene. */
     fun onSceneChanged(scene: SceneModel) {
-        interactor.onSceneChanged(
+        sceneInteractor.onSceneChanged(
             scene = scene,
             loggingReason = SCENE_TRANSITION_LOGGING_REASON,
         )
@@ -60,7 +63,27 @@
      * Note that you must call is with `null` when the UI is done or risk a memory leak.
      */
     fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
-        interactor.setTransitionState(transitionState)
+        sceneInteractor.setTransitionState(transitionState)
+    }
+
+    /**
+     * Notifies that a [MotionEvent] is first seen at the top of the scene container UI.
+     *
+     * Call this before the [MotionEvent] starts to propagate through the UI hierarchy.
+     */
+    fun onMotionEvent(event: MotionEvent) {
+        sceneInteractor.onUserInput()
+        falsingInteractor.onTouchEvent(event)
+    }
+
+    /**
+     * Notifies that a [MotionEvent] that was previously sent to [onMotionEvent] has passed through
+     * the scene container UI.
+     *
+     * Call this after the [MotionEvent] propagates completely through the UI hierarchy.
+     */
+    fun onMotionEventComplete() {
+        falsingInteractor.onMotionEventComplete()
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index a41d6e8..c199904 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -163,6 +163,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -350,6 +351,7 @@
     private final Interpolator mBounceInterpolator;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
+    private final ShadeRepository mShadeRepository;
     private final FalsingTapListener mFalsingTapListener = this::falsingAdditionalTapRequired;
     private final AccessibilityDelegate mAccessibilityDelegate = new ShadeAccessibilityDelegate();
     private final NotificationGutsManager mGutsManager;
@@ -710,7 +712,8 @@
             VibratorHelper vibratorHelper,
             LatencyTracker latencyTracker,
             PowerManager powerManager,
-            AccessibilityManager accessibilityManager, @DisplayId int displayId,
+            AccessibilityManager accessibilityManager,
+            @DisplayId int displayId,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             MetricsLogger metricsLogger,
             ShadeLogger shadeLogger,
@@ -746,6 +749,7 @@
             ScreenOffAnimationController screenOffAnimationController,
             LockscreenGestureLogger lockscreenGestureLogger,
             ShadeExpansionStateManager shadeExpansionStateManager,
+            ShadeRepository shadeRepository,
             Optional<SysUIUnfoldComponent> unfoldComponent,
             SysUiState sysUiState,
             Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider,
@@ -788,6 +792,7 @@
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mLockscreenGestureLogger = lockscreenGestureLogger;
         mShadeExpansionStateManager = shadeExpansionStateManager;
+        mShadeRepository = shadeRepository;
         mShadeLog = shadeLogger;
         mGutsManager = gutsManager;
         mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
@@ -1226,37 +1231,7 @@
     private void updateViewControllers(
             FrameLayout userAvatarView,
             KeyguardUserSwitcherView keyguardUserSwitcherView) {
-        // Re-associate the KeyguardStatusViewController
-        if (mKeyguardStatusViewController != null) {
-            mKeyguardStatusViewController.onDestroy();
-        }
-
-        if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
-            // Need a shared controller until mKeyguardStatusViewController can be removed from
-            // here, due to important state being set in that controller. Rebind in order to pick
-            // up config changes
-            mKeyguardViewConfigurator.bindKeyguardStatusView(mView);
-            mKeyguardStatusViewController =
-                    mKeyguardViewConfigurator.getKeyguardStatusViewController();
-        } else {
-            KeyguardStatusView keyguardStatusView = mView.getRootView().findViewById(
-                    R.id.keyguard_status_view);
-            KeyguardStatusViewComponent statusViewComponent =
-                mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
-            mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
-            mKeyguardStatusViewController.init();
-        }
-        mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
-        mKeyguardStatusViewController.getView().addOnLayoutChangeListener(
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                    int oldHeight = oldBottom - oldTop;
-                    if (v.getHeight() != oldHeight) {
-                        mNotificationStackScrollLayoutController.animateNextTopPaddingChange();
-                    }
-                });
-
-        updateClockAppearance();
-
+        updateStatusBarViewController();
         if (mKeyguardUserSwitcherController != null) {
             // Try to close the switcher so that callbacks are triggered if necessary.
             // Otherwise, NPV can get into a state where some of the views are still hidden
@@ -1286,6 +1261,40 @@
         }
     }
 
+    /** Updates the StatusBarViewController and updates any that depend on it. */
+    public void updateStatusBarViewController() {
+        // Re-associate the KeyguardStatusViewController
+        if (mKeyguardStatusViewController != null) {
+            mKeyguardStatusViewController.onDestroy();
+        }
+
+        if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+            // Need a shared controller until mKeyguardStatusViewController can be removed from
+            // here, due to important state being set in that controller. Rebind in order to pick
+            // up config changes
+            mKeyguardStatusViewController =
+                    mKeyguardViewConfigurator.getKeyguardStatusViewController();
+        } else {
+            KeyguardStatusView keyguardStatusView = mView.getRootView().findViewById(
+                    R.id.keyguard_status_view);
+            KeyguardStatusViewComponent statusViewComponent =
+                    mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
+            mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
+            mKeyguardStatusViewController.init();
+        }
+
+        mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
+        mKeyguardStatusViewController.getView().addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    int oldHeight = oldBottom - oldTop;
+                    if (v.getHeight() != oldHeight) {
+                        mNotificationStackScrollLayoutController.animateNextTopPaddingChange();
+                    }
+                });
+
+        updateClockAppearance();
+    }
+
     @Override
     public void updateResources() {
         final boolean newSplitShadeEnabled =
@@ -1403,7 +1412,8 @@
 
         updateViewControllers(userAvatarView, keyguardUserSwitcherView);
 
-        if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+        if (mFeatureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW) && !mFeatureFlags.isEnabled(
+                Flags.LAZY_INFLATE_KEYGUARD)) {
             attachSplitShadeMediaPlayerContainer(
                     mKeyguardViewConfigurator.getKeyguardRootView()
                         .findViewById(R.id.status_view_media_container));
@@ -2818,7 +2828,6 @@
     }
 
     private void onTrackingStarted() {
-        mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
         endClosing();
         mTracking = true;
         mTrackingStartedListener.onTrackingStarted();
@@ -2834,7 +2843,6 @@
     }
 
     private void onTrackingStopped(boolean expand) {
-        mFalsingCollector.onTrackingStopped();
         mTracking = false;
         maybeStopTrackingExpansionFromStatusBar(expand);
 
@@ -2888,7 +2896,6 @@
 
     @VisibleForTesting
     void onUnlockHintStarted() {
-        mFalsingCollector.onUnlockHintStarted();
         mKeyguardIndicationController.showActionToUnlock();
         mScrimController.setExpansionAffectsAlpha(false);
         mNotificationStackScrollLayoutController.setUnlockHintRunning(true);
@@ -3950,6 +3957,7 @@
             }
             mExpandedFraction = Math.min(1f,
                     maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+            mShadeRepository.setLegacyShadeExpansion(mExpandedFraction);
             mQsController.setShadeExpansion(mExpandedHeight, mExpandedFraction);
             mExpansionDragDownAmountPx = h;
             mAmbientState.setExpansionFraction(mExpandedFraction);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index ad9df72..4a76dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -21,7 +21,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
 
-import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 
 import android.app.IActivityManager;
@@ -52,6 +51,7 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.dump.DumpsysTableLogger;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -76,6 +76,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -104,6 +105,7 @@
     private final float mKeyguardMaxRefreshRate;
     private final KeyguardViewMediator mKeyguardViewMediator;
     private final KeyguardBypassController mKeyguardBypassController;
+    private final Executor mBackgroundExecutor;
     private final AuthController mAuthController;
     private ViewGroup mWindowRootView;
     private LayoutParams mLp;
@@ -141,6 +143,7 @@
             ConfigurationController configurationController,
             KeyguardViewMediator keyguardViewMediator,
             KeyguardBypassController keyguardBypassController,
+            @Background Executor backgroundExecutor,
             SysuiColorExtractor colorExtractor,
             DumpManager dumpManager,
             KeyguardStateController keyguardStateController,
@@ -159,6 +162,7 @@
         mLpChanged = new LayoutParams();
         mKeyguardViewMediator = keyguardViewMediator;
         mKeyguardBypassController = keyguardBypassController;
+        mBackgroundExecutor = backgroundExecutor;
         mColorExtractor = colorExtractor;
         mScreenOffAnimationController = screenOffAnimationController;
         dumpManager.registerDumpable(this);
@@ -520,13 +524,14 @@
         applyWindowLayoutParams();
 
         if (mHasTopUi != mHasTopUiChanged) {
-            whitelistIpcs(() -> {
+            mHasTopUi = mHasTopUiChanged;
+            mBackgroundExecutor.execute(() -> {
                 try {
                     mActivityManager.setHasTopUi(mHasTopUiChanged);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to call setHasTopUi", e);
                 }
-                mHasTopUi = mHasTopUiChanged;
+
             });
         }
         notifyStateChangedCallbacks();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 3a916cf..0f85c76 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -35,6 +35,7 @@
 import com.android.keyguard.KeyguardMessageAreaController;
 import com.android.keyguard.LockIconViewController;
 import com.android.keyguard.dagger.KeyguardBouncerComponent;
+import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.back.domain.interactor.BackActionInteractor;
 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
@@ -43,6 +44,7 @@
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor;
@@ -65,6 +67,8 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.DozeScrimController;
+import com.android.systemui.statusbar.phone.DozeServiceHost;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
@@ -81,7 +85,7 @@
  * Controller for {@link NotificationShadeWindowView}.
  */
 @SysUISingleton
-public class NotificationShadeWindowViewController {
+public class NotificationShadeWindowViewController implements Dumpable {
     private static final String TAG = "NotifShadeWindowVC";
     private final FalsingCollector mFalsingCollector;
     private final SysuiStatusBarStateController mStatusBarStateController;
@@ -118,6 +122,8 @@
     private NotificationStackScrollLayout mStackScrollLayout;
     private PhoneStatusBarViewController mStatusBarViewController;
     private final CentralSurfaces mService;
+    private final DozeServiceHost mDozeServiceHost;
+    private final DozeScrimController mDozeScrimController;
     private final BackActionInteractor mBackActionInteractor;
     private final PowerInteractor mPowerInteractor;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
@@ -152,6 +158,8 @@
             StatusBarWindowStateController statusBarWindowStateController,
             LockIconViewController lockIconViewController,
             CentralSurfaces centralSurfaces,
+            DozeServiceHost dozeServiceHost,
+            DozeScrimController dozeScrimController,
             BackActionInteractor backActionInteractor,
             PowerInteractor powerInteractor,
             NotificationShadeWindowController controller,
@@ -160,6 +168,7 @@
             NotificationInsetsController notificationInsetsController,
             AmbientState ambientState,
             ShadeLogger shadeLogger,
+            DumpManager dumpManager,
             PulsingGestureListener pulsingGestureListener,
             LockscreenHostedDreamGestureListener lockscreenHostedDreamGestureListener,
             KeyguardBouncerViewModel keyguardBouncerViewModel,
@@ -187,8 +196,9 @@
         mLockIconViewController = lockIconViewController;
         mBackActionInteractor = backActionInteractor;
         mShadeLogger = shadeLogger;
-        mLockIconViewController.init();
         mService = centralSurfaces;
+        mDozeServiceHost = dozeServiceHost;
+        mDozeScrimController = dozeScrimController;
         mPowerInteractor = powerInteractor;
         mNotificationShadeWindowController = controller;
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
@@ -226,6 +236,9 @@
                     progressProvider -> progressProvider.addCallback(
                             mDisableSubpixelTextTransitionListener));
         }
+
+        lockIconViewController.setLockIconView(mView.findViewById(R.id.lock_icon_view));
+        dumpManager.registerDumpable(this);
     }
 
     /**
@@ -332,7 +345,7 @@
                 }
 
                 if (mStatusBarStateController.isDozing()) {
-                    mService.extendDozePulse();
+                    mDozeScrimController.extendPulse();
                 }
                 mLockIconViewController.onTouchEvent(
                         ev,
@@ -391,7 +404,7 @@
 
             @Override
             public boolean shouldInterceptTouchEvent(MotionEvent ev) {
-                if (mStatusBarStateController.isDozing() && !mService.isPulsing()
+                if (mStatusBarStateController.isDozing() && !mDozeServiceHost.isPulsing()
                         && !mDockManager.isDocked()) {
                     if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                         mShadeLogger.d("NSWVC: capture all touch events in always-on");
@@ -445,7 +458,7 @@
             public boolean handleTouchEvent(MotionEvent ev) {
                 boolean handled = false;
                 if (mStatusBarStateController.isDozing()) {
-                    handled = !mService.isPulsing();
+                    handled = !mDozeServiceHost.isPulsing();
                 }
 
                 if (mStatusBarKeyguardViewManager.onTouch(ev)) {
@@ -533,6 +546,7 @@
         mAmbientState.setSwipingUp(false);
     }
 
+    @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.print("  mExpandAnimationRunning=");
         pw.println(mExpandAnimationRunning);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index c9c911b..b2bbffd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -67,7 +67,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.classifier.Classifier;
-import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
@@ -147,7 +146,6 @@
     private final MediaHierarchyManager mMediaHierarchyManager;
     private final AmbientState mAmbientState;
     private final RecordingController mRecordingController;
-    private final FalsingCollector mFalsingCollector;
     private final LockscreenGestureLogger mLockscreenGestureLogger;
     private final ShadeLogger mShadeLog;
     private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
@@ -335,7 +333,6 @@
             AmbientState ambientState,
             RecordingController recordingController,
             FalsingManager falsingManager,
-            FalsingCollector falsingCollector,
             AccessibilityManager accessibilityManager,
             LockscreenGestureLogger lockscreenGestureLogger,
             MetricsLogger metricsLogger,
@@ -381,7 +378,6 @@
         mAmbientState = ambientState;
         mRecordingController = recordingController;
         mFalsingManager = falsingManager;
-        mFalsingCollector = falsingCollector;
         mAccessibilityManager = accessibilityManager;
 
         mLockscreenGestureLogger = lockscreenGestureLogger;
@@ -1660,7 +1656,6 @@
                 }
             }
             if (shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
-                mFalsingCollector.onQsDown();
                 mShadeLog.logMotionEvent(event,
                         "handleQsDown: down action, QS tracking enabled");
                 mTracking = true;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index d7a3392..9a3e4e5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -30,6 +30,7 @@
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.dagger.ShadeTouchLog;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -59,6 +60,7 @@
     private final CommandQueue mCommandQueue;
     private final Executor mMainExecutor;
     private final LogBuffer mTouchLog;
+    private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
     private final KeyguardStateController mKeyguardStateController;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final StatusBarStateController mStatusBarStateController;
@@ -83,6 +85,7 @@
             CommandQueue commandQueue,
             @Main Executor mainExecutor,
             @ShadeTouchLog LogBuffer touchLog,
+            WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -97,6 +100,7 @@
         mCommandQueue = commandQueue;
         mMainExecutor = mainExecutor;
         mTouchLog = touchLog;
+        mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
         mShadeViewControllerLazy = shadeViewControllerLazy;
         mStatusBarStateController = statusBarStateController;
         mStatusBarWindowController = statusBarWindowController;
@@ -391,6 +395,7 @@
 
     private void notifyVisibilityChanged(boolean visible) {
         mShadeVisibilityListener.visibilityChanged(visible);
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(visible);
     }
 
     private void notifyExpandedVisibleChanged(boolean expandedVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index 2532bad..b553f0f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -99,9 +99,6 @@
     /** Sets the view's alpha to max. */
     fun resetAlpha()
 
-    /** Sets progress of the predictive back animation. */
-    fun onBackProgressed(progressFraction: Float)
-
     /** @see com.android.systemui.keyguard.ScreenLifecycle.Observer.onScreenTurningOn */
     fun onScreenTurningOn()
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 182a676..1121834 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -155,6 +155,9 @@
     /** Called when Back gesture has been committed (i.e. a back event has definitely occurred) */
     fun onBackPressed()
 
+    /** Sets progress of the predictive back animation. */
+    fun onBackProgressed(progressFraction: Float)
+
     /** Sets whether the status bar launch animation is currently running. */
     fun setIsLaunchAnimationRunning(running: Boolean)
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 09b74b2..6a2bef2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -58,6 +58,7 @@
         return false
     }
     override fun onBackPressed() {}
+    override fun onBackProgressed(progressFraction: Float) {}
     override fun setIsLaunchAnimationRunning(running: Boolean) {}
     override fun setAlpha(alpha: Int, animate: Boolean) {}
     override fun setAlphaChangeAnimationEndAction(r: Runnable) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index 05b1ac6..3f7512a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -22,18 +22,17 @@
 import android.view.LayoutInflater
 import android.view.ViewStub
 import androidx.constraintlayout.motion.widget.MotionLayout
-import com.android.keyguard.LockIconView
 import com.android.systemui.R
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.biometrics.AuthRippleView
-import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.Scene
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.ui.view.SceneWindowRootView
@@ -71,15 +70,13 @@
         @SysUISingleton
         fun providesWindowRootView(
             layoutInflater: LayoutInflater,
-            featureFlags: FeatureFlags,
+            sceneContainerFlags: SceneContainerFlags,
             viewModelProvider: Provider<SceneContainerViewModel>,
             containerConfigProvider: Provider<SceneContainerConfig>,
             scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>,
             layoutInsetController: NotificationInsetsController,
         ): WindowRootView {
-            return if (
-                featureFlags.isEnabled(Flags.SCENE_CONTAINER) && ComposeFacade.isComposeAvailable()
-            ) {
+            return if (sceneContainerFlags.isEnabled()) {
                 val sceneWindowRootView =
                     layoutInflater.inflate(R.layout.scene_window_root, null) as SceneWindowRootView
                 sceneWindowRootView.init(
@@ -96,16 +93,16 @@
                 ?: throw IllegalStateException("Window root view could not be properly inflated")
         }
 
-        @Provides
-        @SysUISingleton
         // TODO(b/277762009): Do something similar to
         //  {@link StatusBarWindowModule.InternalWindowView} so that only
         //  {@link NotificationShadeWindowViewController} can inject this view.
+        @Provides
+        @SysUISingleton
         fun providesNotificationShadeWindowView(
             root: WindowRootView,
-            featureFlags: FeatureFlags,
+            sceneContainerFlags: SceneContainerFlags,
         ): NotificationShadeWindowView {
-            if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+            if (sceneContainerFlags.isEnabled()) {
                 return root.requireViewById(R.id.legacy_window_root)
             }
             return root as NotificationShadeWindowView?
@@ -206,21 +203,6 @@
         // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
         @Provides
         @SysUISingleton
-        fun providesLockIconView(
-            keyguardRootView: KeyguardRootView,
-            notificationPanelView: NotificationPanelView,
-            featureFlags: FeatureFlags
-        ): LockIconView {
-            if (featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)) {
-                return keyguardRootView.requireViewById(R.id.lock_icon_view)
-            } else {
-                return notificationPanelView.requireViewById(R.id.lock_icon_view)
-            }
-        }
-
-        // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
-        @Provides
-        @SysUISingleton
         fun providesTapAgainView(
             notificationPanelView: NotificationPanelView,
         ): TapAgainView {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index 5a8be1e..509921f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -34,21 +34,48 @@
     /** ShadeModel information regarding shade expansion events */
     val shadeModel: Flow<ShadeModel>
 
-    /** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */
+    /**
+     * Amount qs has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded. Quick
+     * Settings can be expanded without the full shade expansion.
+     */
     val qsExpansion: StateFlow<Float>
 
-    /** The amount the shade has expanded */
-    val shadeExpansion: StateFlow<Float>
+    /**
+     * The amount the lockscreen shade has dragged down by the user, [0-1]. 0 means fully collapsed,
+     * 1 means fully expanded.
+     */
+    val lockscreenShadeExpansion: StateFlow<Float>
+
+    /**
+     * NotificationPanelViewController.mExpandedFraction as a StateFlow. This nominally represents
+     * the amount the shade has expanded 0-1 like many other flows in this repo, but there are cases
+     * where its value will be 1 and no shade will be rendered, e.g. whenever the keyguard is
+     * visible and when quick settings is expanded. The confusing nature and impending deletion of
+     * this makes it unsuitable for future development, so usage is discouraged.
+     */
+    @Deprecated("Use ShadeInteractor.shadeExpansion instead")
+    val legacyShadeExpansion: StateFlow<Float>
 
     /** Amount shade has expanded with regard to the UDFPS location */
     val udfpsTransitionToFullShadeProgress: StateFlow<Float>
 
     /** The amount QS has expanded without notifications */
     fun setQsExpansion(qsExpansion: Float)
+
     fun setUdfpsTransitionToFullShadeProgress(progress: Float)
 
-    /** The amount the shade has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded */
-    fun setShadeExpansion(expansion: Float)
+    /**
+     * Set the amount the shade has dragged down by the user, [0-1]. 0 means fully collapsed, 1
+     * means fully expanded.
+     */
+    fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float)
+
+    /**
+     * Set the legacy expansion value. This should only be called whenever the value of
+     * NotificationPanelViewController.mExpandedFraction changes or in tests.
+     */
+    @Deprecated("Should only be called by NPVC and tests")
+    fun setLegacyShadeExpansion(expandedFraction: Float)
 }
 
 /** Business logic for shade interactions */
@@ -84,18 +111,29 @@
     private val _qsExpansion = MutableStateFlow(0f)
     override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
 
-    private val _shadeExpansion = MutableStateFlow(0f)
-    override val shadeExpansion: StateFlow<Float> = _shadeExpansion.asStateFlow()
+    private val _lockscreenShadeExpansion = MutableStateFlow(0f)
+    override val lockscreenShadeExpansion: StateFlow<Float> =
+        _lockscreenShadeExpansion.asStateFlow()
 
     private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
     override val udfpsTransitionToFullShadeProgress: StateFlow<Float> =
         _udfpsTransitionToFullShadeProgress.asStateFlow()
+
+    private val _legacyShadeExpansion = MutableStateFlow(0f)
+    @Deprecated("Use ShadeInteractor.shadeExpansion instead")
+    override val legacyShadeExpansion: StateFlow<Float> = _legacyShadeExpansion.asStateFlow()
+
     override fun setQsExpansion(qsExpansion: Float) {
         _qsExpansion.value = qsExpansion
     }
 
-    override fun setShadeExpansion(expansion: Float) {
-        _shadeExpansion.value = expansion
+    @Deprecated("Should only be called by NPVC and tests")
+    override fun setLegacyShadeExpansion(expandedFraction: Float) {
+        _legacyShadeExpansion.value = expandedFraction
+    }
+
+    override fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) {
+        _lockscreenShadeExpansion.value = lockscreenShadeExpansion
     }
 
     override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 288d32e..fd63b89 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.user.domain.interactor.UserInteractor
@@ -31,6 +32,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
@@ -45,6 +47,7 @@
     userSetupRepository: UserSetupRepository,
     deviceProvisionedController: DeviceProvisionedController,
     userInteractor: UserInteractor,
+    sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
     repository: ShadeRepository,
 ) {
     /** Emits true if the shade is currently allowed and false otherwise. */
@@ -53,16 +56,31 @@
             .map { it.isShadeEnabled() }
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
+    /**
+     * Whether split shade, the combined notifications and quick settings shade used for large
+     * screens, is enabled.
+     */
+    val splitShadeEnabled: Flow<Boolean> =
+        sharedNotificationContainerInteractor.configurationBasedDimensions
+            .map { dimens -> dimens.useSplitShade }
+            .distinctUntilChanged()
+
     /** The amount [0-1] that the shade has been opened */
     val shadeExpansion: Flow<Float> =
-        combine(repository.shadeExpansion, keyguardRepository.statusBarState) {
-            shadeExpansion,
-            statusBarState ->
-            // This is required, as shadeExpansion gets reset to 0f even with the shade open
-            if (statusBarState == StatusBarState.SHADE_LOCKED) {
-                1f
-            } else {
-                shadeExpansion
+        combine(
+            repository.lockscreenShadeExpansion,
+            keyguardRepository.statusBarState,
+            repository.legacyShadeExpansion,
+            repository.qsExpansion,
+            splitShadeEnabled
+        ) { dragDownAmount, statusBarState, legacyShadeExpansion, qsExpansion, splitShadeEnabled ->
+            when (statusBarState) {
+                // legacyShadeExpansion is 1 instead of 0 when QS is expanded
+                StatusBarState.SHADE ->
+                    if (!splitShadeEnabled && qsExpansion > 0f) 0f else legacyShadeExpansion
+                StatusBarState.KEYGUARD -> dragDownAmount
+                // This is required, as shadeExpansion gets reset to 0f even with the shade open
+                StatusBarState.SHADE_LOCKED -> 1f
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
new file mode 100644
index 0000000..c6c664d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.ui.viewmodel
+
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.icu.text.DateFormat
+import android.icu.text.DisplayContext
+import android.os.UserHandle
+import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import java.util.Date
+import java.util.Locale
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Models UI state for the shade header. */
+@SysUISingleton
+class ShadeHeaderViewModel
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    context: Context,
+    sceneInteractor: SceneInteractor,
+    mobileIconsInteractor: MobileIconsInteractor,
+    val mobileIconsViewModel: MobileIconsViewModel,
+    broadcastDispatcher: BroadcastDispatcher,
+) {
+    /** True if we are transitioning between Shade and QuickSettings scenes, in either direction. */
+    val isTransitioning =
+        combine(
+                sceneInteractor.transitioning(from = SceneKey.Shade, to = SceneKey.QuickSettings),
+                sceneInteractor.transitioning(from = SceneKey.QuickSettings, to = SceneKey.Shade)
+            ) { shadeToQuickSettings, quickSettingsToShade ->
+                shadeToQuickSettings || quickSettingsToShade
+            }
+            .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+
+    /** True if there is exactly one mobile connection. */
+    val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier
+
+    /** The list of subscription Ids for current mobile connections. */
+    val mobileSubIds =
+        mobileIconsInteractor.filteredSubscriptions
+            .map { list -> list.map { it.subscriptionId } }
+            .stateIn(applicationScope, SharingStarted.WhileSubscribed(), emptyList())
+
+    private val longerPattern = context.getString(R.string.abbrev_wday_month_day_no_year_alarm)
+    private val shorterPattern = context.getString(R.string.abbrev_month_day_no_year)
+    private val longerDateFormat = MutableStateFlow(getFormatFromPattern(longerPattern))
+    private val shorterDateFormat = MutableStateFlow(getFormatFromPattern(shorterPattern))
+
+    private val _shorterDateText: MutableStateFlow<String> = MutableStateFlow("")
+    val shorterDateText: StateFlow<String> = _shorterDateText.asStateFlow()
+
+    private val _longerDateText: MutableStateFlow<String> = MutableStateFlow("")
+    val longerDateText: StateFlow<String> = _longerDateText.asStateFlow()
+
+    init {
+        broadcastDispatcher
+            .broadcastFlow(
+                filter =
+                    IntentFilter().apply {
+                        addAction(Intent.ACTION_TIME_TICK)
+                        addAction(Intent.ACTION_TIME_CHANGED)
+                        addAction(Intent.ACTION_TIMEZONE_CHANGED)
+                        addAction(Intent.ACTION_LOCALE_CHANGED)
+                    },
+                user = UserHandle.SYSTEM,
+                map = { intent, _ ->
+                    intent.action == Intent.ACTION_TIMEZONE_CHANGED ||
+                        intent.action == Intent.ACTION_LOCALE_CHANGED
+                }
+            )
+            .onEach { invalidateFormats -> updateDateTexts(invalidateFormats) }
+            .launchIn(applicationScope)
+
+        applicationScope.launch { updateDateTexts(false) }
+    }
+
+    private fun updateDateTexts(invalidateFormats: Boolean) {
+        if (invalidateFormats) {
+            longerDateFormat.value = getFormatFromPattern(longerPattern)
+            shorterDateFormat.value = getFormatFromPattern(shorterPattern)
+        }
+
+        val currentTime = Date()
+
+        _longerDateText.value = longerDateFormat.value.format(currentTime)
+        _shorterDateText.value = shorterDateFormat.value.format(currentTime)
+    }
+
+    private fun getFormatFromPattern(pattern: String?): DateFormat {
+        val l = Locale.getDefault()
+        val format = DateFormat.getInstanceForSkeleton(pattern, l)
+        // The use of CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE instead of
+        // CAPITALIZATION_FOR_STANDALONE is to address
+        // https://unicode-org.atlassian.net/browse/ICU-21631
+        // TODO(b/229287642): Switch back to CAPITALIZATION_FOR_STANDALONE
+        format.setContext(DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE)
+        return format
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index 8edc26d..068d5a5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -36,6 +36,7 @@
     @Application private val applicationScope: CoroutineScope,
     authenticationInteractor: AuthenticationInteractor,
     private val bouncerInteractor: BouncerInteractor,
+    val shadeHeaderViewModel: ShadeHeaderViewModel,
 ) {
     /** The key of the scene we should switch to when swiping up. */
     val upDestinationSceneKey: StateFlow<SceneKey> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 25bb204..73bbbca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -81,6 +81,7 @@
     private val powerInteractor: PowerInteractor,
 ) : Dumpable {
     private var pulseHeight: Float = 0f
+
     @get:VisibleForTesting
     var fractionToShade: Float = 0f
         private set
@@ -255,17 +256,17 @@
 
     private fun updateResources() {
         fullTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_full_transition_distance)
+            R.dimen.lockscreen_shade_full_transition_distance)
         fullTransitionDistanceByTap = context.resources.getDimensionPixelSize(
             R.dimen.lockscreen_shade_transition_by_tap_distance)
         notificationShelfTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_notif_shelf_transition_distance)
+            R.dimen.lockscreen_shade_notif_shelf_transition_distance)
         depthControllerTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_depth_controller_transition_distance)
+            R.dimen.lockscreen_shade_depth_controller_transition_distance)
         udfpsTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_udfps_keyguard_transition_distance)
+            R.dimen.lockscreen_shade_udfps_keyguard_transition_distance)
         statusBarTransitionDistance = context.resources.getDimensionPixelSize(
-                R.dimen.lockscreen_shade_status_bar_transition_distance)
+            R.dimen.lockscreen_shade_status_bar_transition_distance)
         useSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
     }
 
@@ -292,8 +293,8 @@
      */
     internal fun canDragDown(): Boolean {
         return (statusBarStateController.state == StatusBarState.KEYGUARD ||
-                nsslController.isInLockedDownShade()) &&
-                (qS.isFullyCollapsed || useSplitShade)
+            nsslController.isInLockedDownShade()) &&
+            (qS.isFullyCollapsed || useSplitShade)
     }
 
     /**
@@ -308,10 +309,15 @@
             if (nsslController.isInLockedDownShade()) {
                 logger.logDraggedDownLockDownShade(startingChild)
                 statusBarStateController.setLeaveOpenOnKeyguardHide(true)
-                activityStarter.dismissKeyguardThenExecute(OnDismissAction {
-                    nextHideKeyguardNeedsNoAnimation = true
-                    false
-                }, cancelRunnable, false /* afterKeyguardGone */)
+                activityStarter.dismissKeyguardThenExecute(
+                    {
+                        nextHideKeyguardNeedsNoAnimation = true
+                        false
+                    },
+                    cancelRunnable,
+                    /* afterKeyguardGone= */
+                    false,
+                )
             } else {
                 logger.logDraggedDown(startingChild, dragLengthY)
                 if (!ambientState.isDozing() || startingChild != null) {
@@ -320,11 +326,18 @@
                     val animationHandler = { delay: Long ->
                         if (startingChild is ExpandableNotificationRow) {
                             startingChild.onExpandedByGesture(
-                                    true /* drag down is always an open */)
+                                true /* drag down is always an open */
+                            )
                         }
                         shadeViewController.transitionToExpandedShade(delay)
-                        callbacks.forEach { it.setTransitionToFullShadeAmount(0f,
-                                true /* animated */, delay) }
+                        callbacks.forEach {
+                            it.setTransitionToFullShadeAmount(
+                                0f,
+                                /* animated= */
+                                true,
+                                delay
+                            )
+                        }
 
                         // Let's reset ourselves, ready for the next animation
 
@@ -350,7 +363,12 @@
      */
     internal fun onDragDownReset() {
         logger.logDragDownAborted()
-        nsslController.setDimmed(true /* dimmed */, true /* animated */)
+        nsslController.setDimmed(
+            /* dimmed= */
+            true,
+            /* animate= */
+            true,
+        )
         nsslController.resetScrollPosition()
         nsslController.resetCheckSnoozeLeavebehind()
         setDragDownAmountAnimated(0f)
@@ -361,7 +379,12 @@
      * @param above whether they dragged above it
      */
     internal fun onCrossedThreshold(above: Boolean) {
-        nsslController.setDimmed(!above /* dimmed */, true /* animate */)
+        nsslController.setDimmed(
+            /* dimmed= */
+            !above,
+            /* animate= */
+            true,
+        )
     }
 
     /**
@@ -411,8 +434,8 @@
      */
     internal val isDragDownAnywhereEnabled: Boolean
         get() = (statusBarStateController.getState() == StatusBarState.KEYGUARD &&
-                !keyguardBypassController.bypassEnabled &&
-                (qS.isFullyCollapsed || useSplitShade))
+            !keyguardBypassController.bypassEnabled &&
+            (qS.isFullyCollapsed || useSplitShade))
 
     /**
      * The amount in pixels that the user has dragged down.
@@ -424,13 +447,20 @@
                 if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
                     fractionToShade =
                         MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
-                    shadeRepository.setShadeExpansion(fractionToShade)
+                    shadeRepository.setLockscreenShadeExpansion(fractionToShade)
                     nsslController.setTransitionToFullShadeAmount(fractionToShade)
 
                     qsTransitionController.dragDownAmount = value
 
-                    callbacks.forEach { it.setTransitionToFullShadeAmount(field,
-                            false /* animate */, 0 /* delay */) }
+                    callbacks.forEach {
+                        it.setTransitionToFullShadeAmount(
+                            field,
+                            /* animate= */
+                            false,
+                            /* delay= */
+                            0,
+                        )
+                    }
 
                     mediaHierarchyManager.setTransitionToFullShadeAmount(field)
                     scrimTransitionController.dragDownAmount = value
@@ -538,8 +568,11 @@
                     shadeViewController.transitionToExpandedShade(delay)
                 }
             }
-            goToLockedShadeInternal(expandedView, animationHandler,
-                    cancelAction = null)
+            goToLockedShadeInternal(
+                expandedView,
+                animationHandler,
+                cancelAction = null
+            )
         }
     }
 
@@ -570,14 +603,19 @@
         var entry: NotificationEntry? = null
         if (expandView is ExpandableNotificationRow) {
             entry = expandView.entry
-            entry.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */)
+            entry.setUserExpanded(
+                /* userExpanded= */
+                true,
+                /* allowChildExpansion= */
+                true,
+            )
             // Indicate that the group expansion is changing at this time -- this way the group
             // and children backgrounds / divider animations will look correct.
             entry.setGroupExpansionChanging(true)
             userId = entry.sbn.userId
         }
         var fullShadeNeedsBouncer = (
-                !lockScreenUserManager.shouldShowLockscreenNotifications() ||
+            !lockScreenUserManager.shouldShowLockscreenNotifications() ||
                 falsingCollector.shouldEnforceBouncer())
         if (keyguardBypassController.bypassEnabled) {
             fullShadeNeedsBouncer = false
@@ -596,7 +634,10 @@
             val cancelHandler = Runnable {
                 draggedDownEntry?.apply {
                     setUserLocked(false)
-                    notifyHeightChanged(false /* needsAnimation */)
+                    notifyHeightChanged(
+                        /* needsAnimation= */
+                        false,
+                    )
                     draggedDownEntry = null
                 }
                 cancelAction?.run()
@@ -614,7 +655,10 @@
             // This call needs to be after updating the shade state since otherwise
             // the scrimstate resets too early
             if (animationHandler != null) {
-                animationHandler.invoke(0 /* delay */)
+                animationHandler.invoke(
+                    /* delay= */
+                    0,
+                )
             } else {
                 performDefaultGoToFullShadeAnimation(0)
             }
@@ -721,12 +765,13 @@
             it.println("isDragDownAnywhereEnabled: $isDragDownAnywhereEnabled")
             it.println("isFalsingCheckNeeded: $isFalsingCheckNeeded")
             it.println("isWakingToShadeLocked: $isWakingToShadeLocked")
-            it.println("hasPendingHandlerOnKeyguardDismiss: " +
-                "${animationHandlerOnKeyguardDismiss != null}")
+            it.println(
+                "hasPendingHandlerOnKeyguardDismiss: " +
+                    "${animationHandlerOnKeyguardDismiss != null}"
+            )
         }
     }
 
-
     fun addCallback(callback: Callback) {
         if (!callbacks.contains(callback)) {
             callbacks.add(callback)
@@ -791,7 +836,7 @@
 
     fun updateResources(context: Context) {
         minDragDistance = context.resources.getDimensionPixelSize(
-                R.dimen.keyguard_drag_down_min_distance)
+            R.dimen.keyguard_drag_down_min_distance)
         val configuration = ViewConfiguration.get(context)
         touchSlop = configuration.scaledTouchSlop.toFloat()
         slopMultiplier = configuration.scaledAmbiguousGestureMultiplier
@@ -808,16 +853,17 @@
                 initialTouchY = y
                 initialTouchX = x
             }
+
             MotionEvent.ACTION_MOVE -> {
                 val h = y - initialTouchY
                 // Adjust the touch slop if another gesture may be being performed.
-                val touchSlop = if (event.classification
-                        == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE)
-                    touchSlop * slopMultiplier
-                else
-                    touchSlop
+                val touchSlop =
+                    if (event.classification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE) {
+                        touchSlop * slopMultiplier
+                    } else {
+                        touchSlop
+                    }
                 if (h > touchSlop && h > Math.abs(x - initialTouchX)) {
-                    falsingCollector.onNotificationStartDraggingDown()
                     isDraggingDown = true
                     captureStartingChild(initialTouchX, initialTouchY)
                     initialTouchY = y
@@ -858,8 +904,9 @@
                 }
                 return true
             }
+
             MotionEvent.ACTION_UP -> if (!falsingManager.isUnlockingDisabled && !isFalseTouch &&
-                    dragDownCallback.canDragDown()) {
+                dragDownCallback.canDragDown()) {
                 dragDownCallback.onDraggedDown(startingChild, (y - initialTouchY).toInt())
                 if (startingChild != null) {
                     expandCallback.setUserLockedChild(startingChild, false)
@@ -870,6 +917,7 @@
                 stopDragging()
                 return false
             }
+
             MotionEvent.ACTION_CANCEL -> {
                 stopDragging()
                 return false
@@ -913,8 +961,8 @@
 
     @VisibleForTesting
     fun cancelChildExpansion(
-            child: ExpandableView,
-            animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS
+        child: ExpandableView,
+        animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS
     ) {
         if (child.actualHeight == child.collapsedHeight) {
             expandCallback.setUserLockedChild(child, false)
@@ -936,7 +984,6 @@
     }
 
     private fun stopDragging() {
-        falsingCollector.onNotificationStopDraggingDown()
         if (startingChild != null) {
             cancelChildExpansion(startingChild!!)
             startingChild = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 763400b..5bd40b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -65,7 +65,6 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.LockscreenWallpaper;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -74,6 +73,8 @@
 import com.android.systemui.util.Utils;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
+import dagger.Lazy;
+
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -87,8 +88,6 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
-import dagger.Lazy;
-
 /**
  * Handles tasks and state related to media notifications. For example, there is a 'current' media
  * notification, which this class keeps track of.
@@ -133,7 +132,6 @@
 
     private final Context mContext;
     private final ArrayList<MediaListener> mMediaListeners;
-    private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
     private final MediaArtworkProcessor mMediaArtworkProcessor;
     private final Set<AsyncTask<?, ?, ?>> mProcessArtworkTasks = new ArraySet<>();
 
@@ -186,7 +184,6 @@
      */
     public NotificationMediaManager(
             Context context,
-            Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             Lazy<NotificationShadeWindowController> notificationShadeWindowController,
             NotificationVisibilityProvider visibilityProvider,
             MediaArtworkProcessor mediaArtworkProcessor,
@@ -205,8 +202,6 @@
         mMediaArtworkProcessor = mediaArtworkProcessor;
         mKeyguardBypassController = keyguardBypassController;
         mMediaListeners = new ArrayList<>();
-        // TODO: use KeyguardStateController#isOccluded to remove this dependency
-        mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
         mNotificationShadeWindowController = notificationShadeWindowController;
         mVisibilityProvider = visibilityProvider;
         mMainExecutor = mainExecutor;
@@ -619,9 +614,7 @@
 
         NotificationShadeWindowController windowController =
                 mNotificationShadeWindowController.get();
-        boolean hideBecauseOccluded =
-                mCentralSurfacesOptionalLazy.get()
-                        .map(CentralSurfaces::isOccluded).orElse(false);
+        boolean hideBecauseOccluded = mKeyguardStateController.isOccluded();
 
         final boolean hasArtwork = artworkDrawable != null;
         mColorExtractor.setHasMediaArtwork(hasMediaArtwork);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index fc6eaa8..2c0741e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -28,10 +28,10 @@
 import android.view.VelocityTracker
 import android.view.ViewConfiguration
 import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
 import com.android.systemui.Dumpable
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
-import com.android.app.animation.Interpolators
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
@@ -76,6 +76,7 @@
     companion object {
         private val SPRING_BACK_ANIMATION_LENGTH_MS = 375
     }
+
     private val mPowerManager: PowerManager?
 
     private var mInitialTouchX: Float = 0.0f
@@ -94,7 +95,10 @@
                         pulseExpandAbortListener?.run()
                     }
                 }
-                headsUpManager.unpinAll(true /* userUnPinned */)
+                headsUpManager.unpinAll(
+                    /*userUnPinned= */
+                    true,
+                )
             }
         }
     var leavingLockscreen: Boolean = false
@@ -168,7 +172,6 @@
             MotionEvent.ACTION_MOVE -> {
                 val h = y - mInitialTouchY
                 if (h > touchSlop && h > Math.abs(x - mInitialTouchX)) {
-                    falsingCollector.onStartExpandingFromPulse()
                     isExpanding = true
                     captureStartingChild(mInitialTouchX, mInitialTouchY)
                     mInitialTouchY = y
@@ -200,14 +203,14 @@
             event.action == MotionEvent.ACTION_UP) && isExpanding
 
         val isDraggingNotificationOrCanBypass = mStartingChild?.showingPulsing() == true ||
-                bypassController.canBypass()
+            bypassController.canBypass()
         if ((!canHandleMotionEvent() || !isDraggingNotificationOrCanBypass) && !finishExpanding) {
             // We allow cancellations/finishing to still go through here to clean up the state
             return false
         }
 
         if (velocityTracker == null || !isExpanding ||
-                event.actionMasked == MotionEvent.ACTION_DOWN) {
+            event.actionMasked == MotionEvent.ACTION_DOWN) {
             return startExpansion(event)
         }
         velocityTracker!!.addMovement(event)
@@ -217,9 +220,12 @@
         when (event.actionMasked) {
             MotionEvent.ACTION_MOVE -> updateExpansionHeight(moveDistance)
             MotionEvent.ACTION_UP -> {
-                velocityTracker!!.computeCurrentVelocity(1000 /* units */)
+                velocityTracker!!.computeCurrentVelocity(
+                    /* units= */
+                    1000,
+                )
                 val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 &&
-                        statusBarStateController.state != StatusBarState.SHADE
+                    statusBarStateController.state != StatusBarState.SHADE
                 if (!falsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
                     finishExpansion()
                 } else {
@@ -227,6 +233,7 @@
                 }
                 recycleVelocityTracker()
             }
+
             MotionEvent.ACTION_CANCEL -> {
                 cancelExpansion()
                 recycleVelocityTracker()
@@ -243,17 +250,25 @@
         }
         if (statusBarStateController.isDozing) {
             wakeUpCoordinator.willWakeUp = true
-            mPowerManager!!.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
-                    "com.android.systemui:PULSEDRAG")
+            mPowerManager!!.wakeUp(
+                SystemClock.uptimeMillis(),
+                PowerManager.WAKE_REASON_GESTURE,
+                "com.android.systemui:PULSEDRAG"
+            )
         }
-        lockscreenShadeTransitionController.goToLockedShade(startingChild,
-                needsQSAnimation = false)
+        lockscreenShadeTransitionController.goToLockedShade(
+            startingChild,
+            needsQSAnimation = false
+        )
         lockscreenShadeTransitionController.finishPulseAnimation(cancelled = false)
         leavingLockscreen = true
         isExpanding = false
         if (mStartingChild is ExpandableNotificationRow) {
             val row = mStartingChild as ExpandableNotificationRow?
-            row!!.onExpandedByGesture(true /* userExpanded */)
+            row!!.onExpandedByGesture(
+                /*userExpanded= */
+                true,
+            )
         }
     }
 
@@ -261,15 +276,20 @@
         var expansionHeight = max(height, 0.0f)
         if (mStartingChild != null) {
             val child = mStartingChild!!
-            val newHeight = Math.min((child.collapsedHeight + expansionHeight).toInt(),
-                    child.maxContentHeight)
+            val newHeight = Math.min(
+                (child.collapsedHeight + expansionHeight).toInt(),
+                child.maxContentHeight
+            )
             child.actualHeight = newHeight
         } else {
             wakeUpCoordinator.setNotificationsVisibleForExpansion(
                 height
                     > lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications,
-                true /* animate */,
-                true /* increaseSpeed */)
+                /*animate= */
+                true,
+                /*increaseSpeed= */
+                true
+            )
         }
         lockscreenShadeTransitionController.setPulseHeight(expansionHeight, animate = false)
     }
@@ -285,8 +305,8 @@
 
     @VisibleForTesting
     fun reset(
-            child: ExpandableView,
-            animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
+        child: ExpandableView,
+        animationDuration: Long = SPRING_BACK_ANIMATION_LENGTH_MS.toLong()
     ) {
         if (child.actualHeight == child.collapsedHeight) {
             setUserLocked(child, false)
@@ -315,15 +335,19 @@
 
     private fun cancelExpansion() {
         isExpanding = false
-        falsingCollector.onExpansionFromPulseStopped()
         if (mStartingChild != null) {
             reset(mStartingChild!!)
             mStartingChild = null
         }
         lockscreenShadeTransitionController.finishPulseAnimation(cancelled = true)
-        wakeUpCoordinator.setNotificationsVisibleForExpansion(false /* visible */,
-                true /* animate */,
-                false /* increaseSpeed */)
+        wakeUpCoordinator.setNotificationsVisibleForExpansion(
+            /*visible= */
+            false,
+            /*animate= */
+            true,
+            /*increaseSpeed= */
+            false
+        )
     }
 
     private fun findView(x: Float, y: Float): ExpandableView? {
@@ -335,7 +359,9 @@
         val childAtRawPosition = stackScrollerController.getChildAtRawPosition(totalX, totalY)
         return if (childAtRawPosition != null && childAtRawPosition.isContentExpandable) {
             childAtRawPosition
-        } else null
+        } else {
+            null
+        }
     }
 
     fun setUp(stackScrollerController: NotificationStackScrollLayoutController) {
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 92aa986..b46b525 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityModule.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.connectivity
 
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags.SIGNAL_CALLBACK_DEPRECATION
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.qs.tiles.AirplaneModeTile
 import com.android.systemui.qs.tiles.BluetoothTile
@@ -23,21 +25,17 @@
 import com.android.systemui.qs.tiles.DataSaverTile
 import com.android.systemui.qs.tiles.HotspotTile
 import com.android.systemui.qs.tiles.InternetTile
+import com.android.systemui.qs.tiles.InternetTileNewImpl
 import com.android.systemui.qs.tiles.NfcTile
 import dagger.Binds
 import dagger.Module
+import dagger.Provides
 import dagger.multibindings.IntoMap
 import dagger.multibindings.StringKey
 
 @Module
 interface ConnectivityModule {
 
-    /** Inject InternetTile into tileMap in QSModule */
-    @Binds
-    @IntoMap
-    @StringKey(InternetTile.TILE_SPEC)
-    fun bindInternetTile(internetTile: InternetTile): QSTileImpl<*>
-
     /** Inject BluetoothTile into tileMap in QSModule */
     @Binds
     @IntoMap
@@ -70,4 +68,21 @@
 
     /** Inject NfcTile into tileMap in QSModule */
     @Binds @IntoMap @StringKey(NfcTile.TILE_SPEC) fun bindNfcTile(nfcTile: NfcTile): QSTileImpl<*>
+
+    companion object {
+        /** Inject InternetTile or InternetTileNewImpl into tileMap in QSModule */
+        @Provides
+        @IntoMap
+        @StringKey(InternetTile.TILE_SPEC)
+        fun bindInternetTile(
+            internetTile: InternetTile,
+            newInternetTile: InternetTileNewImpl,
+            featureFlags: FeatureFlags,
+        ): QSTileImpl<*> =
+            if (featureFlags.isEnabled(SIGNAL_CALLBACK_DEPRECATION)) {
+                newInternetTile
+            } else {
+                internetTile
+            }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 2ad71e7..80274bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import java.lang.IllegalStateException
 import javax.inject.Inject
+import javax.inject.Provider
 
 /**
  * Responsible for creating the status bar window and initializing the root components of that
@@ -35,6 +36,7 @@
 @SysUISingleton
 class StatusBarInitializer @Inject constructor(
     private val windowController: StatusBarWindowController,
+    private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
     private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
 ) {
 
@@ -43,11 +45,9 @@
     /**
      * Creates the status bar window and root views, and initializes the component.
      *
-     * TODO(b/277762009): Inject StatusBarFragmentCreator and make this class a CoreStartable.
+     * TODO(b/277764509): Initialize the status bar via [CoreStartable#start].
      */
-    fun initializeStatusBar(
-        statusBarFragmentCreator: () -> CollapsedStatusBarFragment,
-    ) {
+    fun initializeStatusBar() {
         windowController.fragmentHostManager.addTagListener(
                 CollapsedStatusBarFragment.TAG,
                 object : FragmentHostManager.FragmentListener {
@@ -67,11 +67,14 @@
                     override fun onFragmentViewDestroyed(tag: String?, fragment: Fragment?) {
                         // nop
                     }
-                }).fragmentManager
+                }
+        ).fragmentManager
                 .beginTransaction()
-                .replace(R.id.status_bar_container,
-                        statusBarFragmentCreator.invoke(),
-                        CollapsedStatusBarFragment.TAG)
+                .replace(
+                    R.id.status_bar_container,
+                    collapsedStatusBarFragmentProvider.get(),
+                    CollapsedStatusBarFragment.TAG
+                )
                 .commit()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index f726c4e..3dfe068 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -64,7 +64,6 @@
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -135,7 +134,6 @@
     @Provides
     static NotificationMediaManager provideNotificationMediaManager(
             Context context,
-            Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             Lazy<NotificationShadeWindowController> notificationShadeWindowController,
             NotificationVisibilityProvider visibilityProvider,
             MediaArtworkProcessor mediaArtworkProcessor,
@@ -152,7 +150,6 @@
             DisplayManager displayManager) {
         return new NotificationMediaManager(
                 context,
-                centralSurfacesOptionalLazy,
                 notificationShadeWindowController,
                 visibilityProvider,
                 mediaArtworkProcessor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
index f40f570..a3bc002 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImpl.kt
@@ -132,8 +132,9 @@
     override fun onStatusEvent(event: StatusEvent) {
         Assert.isMainThread()
 
-        // Ignore any updates until the system is up and running
-        if (isTooEarly() || !isImmersiveIndicatorEnabled()) {
+        // Ignore any updates until the system is up and running. However, for important events that
+        // request to be force visible (like privacy), ignore whether it's too early.
+        if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) {
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt
index 5fa83ef..6b5a548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerLegacyImpl.kt
@@ -93,8 +93,9 @@
     @SystemAnimationState override fun getAnimationState() = animationState
 
     override fun onStatusEvent(event: StatusEvent) {
-        // Ignore any updates until the system is up and running
-        if (isTooEarly() || !isImmersiveIndicatorEnabled()) {
+        // Ignore any updates until the system is up and running. However, for important events that
+        // request to be force visible (like privacy), ignore whether it's too early.
+        if ((isTooEarly() && !event.forceVisible) || !isImmersiveIndicatorEnabled()) {
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index d248961..6e3b15d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationContentInflaterLogger
 import com.android.systemui.statusbar.notification.row.NotificationContentView
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -47,7 +48,11 @@
     private val launcherApps: LauncherApps,
     private val conversationNotificationManager: ConversationNotificationManager
 ) {
-    fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) {
+    fun processNotification(
+            entry: NotificationEntry,
+            recoveredBuilder: Notification.Builder,
+            logger: NotificationContentInflaterLogger
+    ) {
         val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
         messagingStyle.conversationType =
                 if (entry.ranking.channel.isImportantConversation)
@@ -55,6 +60,7 @@
                 else
                     Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
         entry.ranking.conversationShortcutInfo?.let { shortcutInfo ->
+            logger.logAsyncTaskProgress(entry, "getting shortcut icon")
             messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
             shortcutInfo.label?.let { label ->
                 messagingStyle.conversationTitle = label
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index d1aa01b..98109f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -36,12 +36,14 @@
 public class NotifInflaterImpl implements NotifInflater {
 
     private final NotifInflationErrorManager mNotifErrorManager;
+    private final NotifInflaterLogger mLogger;
 
     private NotificationRowBinderImpl mNotificationRowBinder;
 
     @Inject
-    public NotifInflaterImpl(NotifInflationErrorManager errorManager) {
+    public NotifInflaterImpl(NotifInflationErrorManager errorManager, NotifInflaterLogger logger) {
         mNotifErrorManager = errorManager;
+        mLogger = logger;
     }
 
     /**
@@ -51,12 +53,6 @@
         mNotificationRowBinder = rowBinder;
     }
 
-    @Override
-    public void rebindViews(@NonNull NotificationEntry entry, @NonNull Params params,
-            @NonNull InflationCallback callback) {
-        inflateViews(entry, params, callback);
-    }
-
     /**
      * Called to inflate the views of an entry.  Views are not considered inflated until all of its
      * views are bound.
@@ -64,23 +60,43 @@
     @Override
     public void inflateViews(@NonNull NotificationEntry entry, @NonNull Params params,
             @NonNull InflationCallback callback) {
+        mLogger.logInflatingViews(entry, params);
+        inflateViewsImpl(entry, params, callback);
+        mLogger.logInflatedViews(entry);
+    }
+    @Override
+    public void rebindViews(@NonNull NotificationEntry entry, @NonNull Params params,
+            @NonNull InflationCallback callback) {
+        mLogger.logRebindingViews(entry, params);
+        inflateViewsImpl(entry, params, callback);
+        mLogger.logReboundViews(entry);
+    }
+
+    private void inflateViewsImpl(@NonNull NotificationEntry entry, @NonNull Params params,
+            @NonNull InflationCallback callback) {
         try {
             requireBinder().inflateViews(
                     entry,
                     params,
                     wrapInflationCallback(callback));
         } catch (InflationException e) {
+            mLogger.logInflationException(entry, e);
             mNotifErrorManager.setInflationError(entry, e);
         }
     }
 
     @Override
     public boolean abortInflation(NotificationEntry entry) {
-        return entry.abortTask();
+        final boolean abortedTask = entry.abortTask();
+        if (abortedTask) {
+            mLogger.logAbortInflationAbortedTask(entry);
+        }
+        return abortedTask;
     }
 
     @Override
     public void releaseViews(@NonNull NotificationEntry entry) {
+        mLogger.logReleasingViews(entry);
         requireBinder().releaseViews(entry);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterLogger.kt
new file mode 100644
index 0000000..366c7d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterLogger.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.statusbar.notification.InflationException
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater.Params
+import com.android.systemui.statusbar.notification.logKey
+import javax.inject.Inject
+
+class NotifInflaterLogger @Inject constructor(@NotifInflationLog private val buffer: LogBuffer) {
+    fun logInflatingViews(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "inflating views for $str1: $str2" }
+        )
+    }
+
+    fun logInflatedViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "inflated views for $str1" })
+    }
+
+    fun logRebindingViews(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "rebinding views for $str1: $str2" }
+        )
+    }
+
+    fun logReboundViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "rebound views for $str1" })
+    }
+
+    fun logInflationException(entry: NotificationEntry, exc: InflationException) {
+        buffer.log(
+            TAG,
+            LogLevel.WARNING,
+            {
+                str1 = entry.logKey
+                str2 = exc.stackTraceToString()
+            },
+            { "exception inflating views for $str1: $str2" }
+        )
+    }
+
+    fun logAbortInflationAbortedTask(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            { str1 = entry.logKey },
+            { "aborted task to abort inflation for $str1" }
+        )
+    }
+
+    fun logReleasingViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "aborting inflation for $str1" })
+    }
+}
+
+private const val TAG = "NotifInflater"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index 5c2f9a8..62a0d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -39,10 +39,7 @@
 
     override fun attach(pipeline: NotifPipeline) {
         pipeline.addOnAfterRenderListListener(::onAfterRenderList)
-        // TODO(b/282865576): This has an issue where it makes changes to some groups without
-        // notifying listeners. To be fixed in QPR, but for now let's comment it out to avoid the
-        // group expansion bug.
-        // groupExpansionManagerImpl.attach(pipeline)
+        groupExpansionManagerImpl.attach(pipeline)
     }
 
     fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
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 9ecf50e..e206141 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
@@ -67,6 +67,7 @@
     private final ExpandableNotificationRowComponent.Builder
             mExpandableNotificationRowComponentBuilder;
     private final IconManager mIconManager;
+    private final NotificationRowBinderLogger mLogger;
 
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
@@ -84,6 +85,7 @@
             Provider<RowInflaterTask> rowInflaterTaskProvider,
             ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
             IconManager iconManager,
+            NotificationRowBinderLogger logger,
             FeatureFlags featureFlags) {
         mContext = context;
         mNotifBindPipeline = notifBindPipeline;
@@ -94,6 +96,7 @@
         mRowInflaterTaskProvider = rowInflaterTaskProvider;
         mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
         mIconManager = iconManager;
+        mLogger = logger;
         mFeatureFlags = featureFlags;
     }
 
@@ -124,15 +127,19 @@
         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
 
         if (entry.rowExists()) {
+            mLogger.logUpdatingRow(entry, params);
             mIconManager.updateIcons(entry);
             ExpandableNotificationRow row = entry.getRow();
             row.reset();
             updateRow(entry, row);
             inflateContentViews(entry, params, row, callback);
         } else {
+            mLogger.logCreatingRow(entry, params);
             mIconManager.createIcons(entry);
+            mLogger.logInflatingRow(entry);
             mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
                     row -> {
+                        mLogger.logInflatedRow(entry);
                         // Setup the controller for the view.
                         ExpandableNotificationRowComponent component =
                                 mExpandableNotificationRowComponentBuilder
@@ -154,8 +161,10 @@
     @Override
     public void releaseViews(NotificationEntry entry) {
         if (!entry.rowExists()) {
+            mLogger.logNotReleasingViewsRowDoesntExist(entry);
             return;
         }
+        mLogger.logReleasingViews(entry);
         final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
@@ -220,7 +229,9 @@
         }
 
         params.rebindAllContentViews();
+        mLogger.logRequestingRebind(entry, inflaterParams);
         mRowContentBindStage.requestRebind(entry, en -> {
+            mLogger.logRebindComplete(entry);
             row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
             row.setIsLowPriority(isLowPriority);
             if (inflationCallback != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderLogger.kt
new file mode 100644
index 0000000..7eafc59
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderLogger.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.inflation
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater.Params
+import com.android.systemui.statusbar.notification.logKey
+import javax.inject.Inject
+
+class NotificationRowBinderLogger
+@Inject
+constructor(@NotifInflationLog private val buffer: LogBuffer) {
+    fun logCreatingRow(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "creating row for $str1: $str2" }
+        )
+    }
+
+    fun logInflatingRow(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "inflating row for $str1" })
+    }
+
+    fun logInflatedRow(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "inflated row for $str1" })
+    }
+
+    fun logUpdatingRow(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "updating row for $str1: $str2" }
+        )
+    }
+
+    fun logReleasingViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "releasing views for $str1" })
+    }
+
+    fun logNotReleasingViewsRowDoesntExist(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            { str1 = entry.logKey },
+            { "not releasing views for $str1: row doesn't exist" }
+        )
+    }
+
+    fun logRequestingRebind(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.key
+                str2 = params.reason
+            },
+            { "requesting rebind for $str1: $str2" }
+        )
+    }
+
+    fun logRebindComplete(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.key }, { "rebind complete for $str1" })
+    }
+}
+
+private const val TAG = "NotificationRowBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
index 46af03a..eb31bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -67,18 +67,29 @@
      * Cleanup entries from mExpandedGroups that no longer exist in the pipeline.
      */
     private final OnBeforeRenderListListener mNotifTracker = (entries) -> {
+        if (mExpandedGroups.isEmpty()) {
+            return; // nothing to do
+        }
+
         final Set<NotificationEntry> renderingSummaries = new HashSet<>();
         for (ListEntry entry : entries) {
             if (entry instanceof GroupEntry) {
                 renderingSummaries.add(entry.getRepresentativeEntry());
             }
         }
-        mExpandedGroups.removeIf(expandedGroup -> !renderingSummaries.contains(expandedGroup));
+
+        // If a group is in mExpandedGroups but not in the pipeline entries, collapse it.
+        final var groupsToRemove = setDifference(mExpandedGroups, renderingSummaries);
+        for (NotificationEntry entry : groupsToRemove) {
+            setGroupExpanded(entry, false);
+        }
     };
 
     public void attach(NotifPipeline pipeline) {
-        mDumpManager.registerDumpable(this);
-        pipeline.addOnBeforeRenderListListener(mNotifTracker);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+            mDumpManager.registerDumpable(this);
+            pipeline.addOnBeforeRenderListListener(mNotifTracker);
+        }
     }
 
     @Override
@@ -134,4 +145,27 @@
             listener.onGroupExpansionChange(entry.getRow(), expanded);
         }
     }
+
+    /**
+     * Utility method to compute the difference between two sets of NotificationEntry. Unfortunately
+     * {@code Sets.difference} from Guava is not available in this codebase.
+     */
+    @NonNull
+    private Set<NotificationEntry> setDifference(Set<NotificationEntry> set1,
+            Set<NotificationEntry> set2) {
+        if (set1 == null || set1.isEmpty()) {
+            return new HashSet<>();
+        }
+        if (set2 == null || set2.isEmpty()) {
+            return new HashSet<>(set1);
+        }
+
+        final Set<NotificationEntry> difference = new HashSet<>();
+        for (NotificationEntry e : set1) {
+            if (!set2.contains(e)) {
+                difference.add(e);
+            }
+        }
+        return difference;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
index b9c8f72..c33e8ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.render;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 
 import com.android.systemui.statusbar.notification.collection.ListEntry;
@@ -31,13 +32,14 @@
      * @return whether a given notification is a top level entry or is the summary in a group which
      * has children
      */
-    boolean isGroupSummary(NotificationEntry entry);
+    boolean isGroupSummary(@NonNull NotificationEntry entry);
 
     /**
      * Get the summary of a specified status bar notification. For an isolated notification this
      * returns itself.
      */
-    NotificationEntry getGroupSummary(NotificationEntry entry);
+    @Nullable
+    NotificationEntry getGroupSummary(@NonNull NotificationEntry entry);
 
     /**
      * Similar to {@link #getGroupSummary(NotificationEntry)} but doesn't get the visual summary
@@ -46,19 +48,20 @@
      * TODO: remove this when migrating to the new pipeline, this is taken care of in the
      * dismissal logic built into NotifCollection
      */
-    default NotificationEntry getLogicalGroupSummary(NotificationEntry entry) {
+    @Nullable
+    default NotificationEntry getLogicalGroupSummary(@NonNull NotificationEntry entry) {
         return getGroupSummary(entry);
     }
 
     /**
      * @return whether a given notification is a child in a group
      */
-    boolean isChildInGroup(NotificationEntry entry);
+    boolean isChildInGroup(@NonNull NotificationEntry entry);
 
     /**
      * Whether this is the only child in a group
      */
-    boolean isOnlyChildInGroup(NotificationEntry entry);
+    boolean isOnlyChildInGroup(@NonNull NotificationEntry entry);
 
     /**
      * Get the children that are in the summary's group, not including those isolated.
@@ -67,5 +70,5 @@
      * @return list of the children
      */
     @Nullable
-    List<NotificationEntry> getChildren(ListEntry summary);
+    List<NotificationEntry> getChildren(@NonNull ListEntry summary);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
index e784ec6..a6b855f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
@@ -18,40 +18,65 @@
 
 import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import java.util.List;
 
+import javax.inject.Inject;
+
 /**
  * ShadeListBuilder groups notifications from system server. This manager translates
  * ShadeListBuilder's method of grouping to be used within SystemUI.
  */
+@SysUISingleton
 public class GroupMembershipManagerImpl implements GroupMembershipManager {
-    @Override
-    public boolean isGroupSummary(NotificationEntry entry) {
-        return getGroupSummary(entry) == entry;
+    FeatureFlags mFeatureFlags;
+
+    @Inject
+    public GroupMembershipManagerImpl(FeatureFlags featureFlags) {
+        mFeatureFlags = featureFlags;
     }
 
     @Override
-    public NotificationEntry getGroupSummary(NotificationEntry entry) {
-        if (isEntryTopLevel(entry) || entry.getParent() == null) {
-            return null;
+    public boolean isGroupSummary(@NonNull NotificationEntry entry) {
+        return getGroupSummary(entry) == entry;
+    }
+
+    @Nullable
+    @Override
+    public NotificationEntry getGroupSummary(@NonNull NotificationEntry entry) {
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+            if (!isChildInGroup(entry)) {
+                return entry.getRepresentativeEntry();
+            }
+        } else {
+            if (isEntryTopLevel(entry) || entry.getParent() == null) {
+                return null;
+            }
         }
 
         return entry.getParent().getRepresentativeEntry();
     }
 
     @Override
-    public boolean isChildInGroup(NotificationEntry entry) {
-        return !isEntryTopLevel(entry);
+    public boolean isChildInGroup(@NonNull NotificationEntry entry) {
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+            return !isEntryTopLevel(entry) && entry.getParent() != null;
+        } else {
+            return !isEntryTopLevel(entry);
+        }
     }
 
     @Override
-    public boolean isOnlyChildInGroup(NotificationEntry entry) {
+    public boolean isOnlyChildInGroup(@NonNull NotificationEntry entry) {
         if (entry.getParent() == null) {
             return false;
         }
@@ -61,20 +86,24 @@
 
     @Nullable
     @Override
-    public List<NotificationEntry> getChildren(ListEntry entry) {
+    public List<NotificationEntry> getChildren(@NonNull ListEntry entry) {
         if (entry instanceof GroupEntry) {
             return ((GroupEntry) entry).getChildren();
         }
 
-        if (isGroupSummary(entry.getRepresentativeEntry())) {
+        NotificationEntry representativeEntry = entry.getRepresentativeEntry();
+        if (representativeEntry != null && isGroupSummary(representativeEntry)) {
             // maybe we were actually passed the summary
-            return entry.getRepresentativeEntry().getParent().getChildren();
+            GroupEntry parent = representativeEntry.getParent();
+            if (parent != null) {
+                return parent.getChildren();
+            }
         }
 
         return null;
     }
 
-    private boolean isEntryTopLevel(NotificationEntry entry) {
+    private boolean isEntryTopLevel(@NonNull NotificationEntry entry) {
         return entry.getParent() == ROOT_ENTRY;
     }
 }
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 637637d..5664a2a 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
@@ -19,12 +19,13 @@
 import android.content.Context;
 
 import com.android.internal.jank.InteractionJankMonitor;
+import com.android.systemui.CoreStartable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.shade.ShadeEventsModule;
-import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
@@ -76,10 +77,13 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.util.kotlin.JavaAdapter;
 
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
 
 import java.util.concurrent.Executor;
 
@@ -110,6 +114,13 @@
     @Binds
     NotifGutsViewManager bindNotifGutsViewManager(NotificationGutsManager notificationGutsManager);
 
+    /** Binds {@link NotificationGutsManager} as a {@link CoreStartable}. */
+    @Binds
+    @IntoMap
+    @ClassKey(NotificationGutsManager.class)
+    CoreStartable bindsNotificationGutsManager(NotificationGutsManager notificationGutsManager);
+
+
     /** Provides an instance of {@link VisibilityLocationProvider} */
     @Binds
     VisibilityLocationProvider bindVisibilityLocationProvider(
@@ -125,7 +136,8 @@
             NotificationVisibilityProvider visibilityProvider,
             NotifPipeline notifPipeline,
             StatusBarStateController statusBarStateController,
-            ShadeExpansionStateManager shadeExpansionStateManager,
+            WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
+            JavaAdapter javaAdapter,
             NotificationLogger.ExpansionStateLogger expansionStateLogger,
             NotificationPanelLogger notificationPanelLogger) {
         return new NotificationLogger(
@@ -135,11 +147,18 @@
                 visibilityProvider,
                 notifPipeline,
                 statusBarStateController,
-                shadeExpansionStateManager,
+                windowRootViewVisibilityInteractor,
+                javaAdapter,
                 expansionStateLogger,
                 notificationPanelLogger);
     }
 
+    /** Binds {@link NotificationLogger} as a {@link CoreStartable}. */
+    @Binds
+    @IntoMap
+    @ClassKey(NotificationLogger.class)
+    CoreStartable bindsNotificationLogger(NotificationLogger notificationLogger);
+
     /** Provides an instance of {@link NotificationPanelLogger} */
     @SysUISingleton
     @Provides
@@ -148,11 +167,8 @@
     }
 
     /** Provides an instance of {@link GroupMembershipManager} */
-    @SysUISingleton
-    @Provides
-    static GroupMembershipManager provideGroupMembershipManager() {
-        return new GroupMembershipManagerImpl();
-    }
+    @Binds
+    GroupMembershipManager provideGroupMembershipManager(GroupMembershipManagerImpl impl);
 
     /** Provides an instance of {@link GroupExpansionManager} */
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 26f97de..8d2a63e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -33,10 +33,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
@@ -48,6 +49,7 @@
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.util.Compile;
+import com.android.systemui.util.kotlin.JavaAdapter;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -62,7 +64,7 @@
  * Handles notification logging, in particular, logging which notifications are visible and which
  * are not.
  */
-public class NotificationLogger implements StateListener {
+public class NotificationLogger implements StateListener, CoreStartable {
     static final String TAG = "NotificationLogger";
     private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
 
@@ -81,6 +83,8 @@
     private final NotifPipeline mNotifPipeline;
     private final NotificationPanelLogger mNotificationPanelLogger;
     private final ExpansionStateLogger mExpansionStateLogger;
+    private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
+    private final JavaAdapter mJavaAdapter;
 
     protected Handler mHandler = new Handler();
     protected IStatusBarService mBarService;
@@ -88,10 +92,7 @@
     private NotificationListContainer mListContainer;
     private final Object mDozingLock = new Object();
     @GuardedBy("mDozingLock")
-    private Boolean mDozing = null;  // Use null to indicate state is not yet known
-    @GuardedBy("mDozingLock")
     private Boolean mLockscreen = null;  // Use null to indicate state is not yet known
-    private Boolean mPanelExpanded = null;  // Use null to indicate state is not yet known
     private boolean mLogging = false;
 
     // Tracks notifications currently visible in mNotificationStackScroller and
@@ -202,7 +203,8 @@
             NotificationVisibilityProvider visibilityProvider,
             NotifPipeline notifPipeline,
             StatusBarStateController statusBarStateController,
-            ShadeExpansionStateManager shadeExpansionStateManager,
+            WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
+            JavaAdapter javaAdapter,
             ExpansionStateLogger expansionStateLogger,
             NotificationPanelLogger notificationPanelLogger) {
         mNotificationListener = notificationListener;
@@ -214,9 +216,10 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mExpansionStateLogger = expansionStateLogger;
         mNotificationPanelLogger = notificationPanelLogger;
+        mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
+        mJavaAdapter = javaAdapter;
         // Not expected to be destroyed, don't need to unsubscribe
         statusBarStateController.addCallback(this);
-        shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged);
 
         registerNewPipelineListener();
     }
@@ -239,6 +242,22 @@
         mListContainer = listContainer;
     }
 
+    @Override
+    public void start() {
+        mJavaAdapter.alwaysCollectFlow(
+                mWindowRootViewVisibilityInteractor.isLockscreenOrShadeVisibleAndInteractive(),
+                this::onLockscreenOrShadeVisibleAndInteractiveChanged);
+    }
+
+    private void onLockscreenOrShadeVisibleAndInteractiveChanged(boolean visible) {
+        if (visible) {
+            startNotificationLogging();
+        } else {
+            // Ensure we stop notification logging when the device isn't interactive.
+            stopNotificationLogging();
+        }
+    }
+
     public void stopNotificationLogging() {
         if (mLogging) {
             mLogging = false;
@@ -263,10 +282,15 @@
             if (DEBUG) {
                 Log.i(TAG, "startNotificationLogging");
             }
+            boolean lockscreen;
+            synchronized (mDozingLock) {
+                lockscreen = mLockscreen != null && mLockscreen;
+            }
+            mNotificationPanelLogger.logPanelShown(lockscreen, getVisibleNotifications());
             mListContainer.setChildLocationsChangedListener(this::onChildLocationsChanged);
-            // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
-            // cause the scroller to emit child location events. Hence generate
-            // one ourselves to guarantee that we're reporting visible
+            // Sometimes, the transition from lockscreenOrShadeVisible=false ->
+            // lockscreenOrShadeVisible=true doesn't cause the scroller to emit child location
+            // events. Hence generate one ourselves to guarantee that we're reporting visible
             // notifications.
             // (Note that in cases where the scroller does emit events, this
             // additional event doesn't break anything.)
@@ -274,13 +298,6 @@
         }
     }
 
-    private void setDozing(boolean dozing) {
-        synchronized (mDozingLock) {
-            mDozing = dozing;
-            maybeUpdateLoggingStatus();
-        }
-    }
-
     private void logNotificationVisibilityChanges(
             Collection<NotificationVisibility> newlyVisible,
             Collection<NotificationVisibility> noLongerVisible) {
@@ -362,39 +379,6 @@
         }
     }
 
-    @Override
-    public void onDozingChanged(boolean isDozing) {
-        if (DEBUG) {
-            Log.i(TAG, "onDozingChanged: new=" + isDozing);
-        }
-        setDozing(isDozing);
-    }
-
-    @GuardedBy("mDozingLock")
-    private void maybeUpdateLoggingStatus() {
-        if (mPanelExpanded == null || mDozing == null) {
-            if (DEBUG) {
-                Log.i(TAG, "Panel status unclear: panelExpandedKnown="
-                        + (mPanelExpanded == null) + " dozingKnown=" + (mDozing == null));
-            }
-            return;
-        }
-        // Once we know panelExpanded and Dozing, turn logging on & off when appropriate
-        boolean lockscreen = mLockscreen == null ? false : mLockscreen;
-        if (mPanelExpanded && !mDozing) {
-            mNotificationPanelLogger.logPanelShown(lockscreen, getVisibleNotifications());
-            if (DEBUG) {
-                Log.i(TAG, "Notification panel shown, lockscreen=" + lockscreen);
-            }
-            startNotificationLogging();
-        } else {
-            if (DEBUG) {
-                Log.i(TAG, "Notification panel hidden, lockscreen=" + lockscreen);
-            }
-            stopNotificationLogging();
-        }
-    }
-
     /**
      * Called when the notification is expanded / collapsed.
      */
@@ -404,20 +388,6 @@
     }
 
     @VisibleForTesting
-    void onShadeExpansionFullyChanged(Boolean isExpanded) {
-        // mPanelExpanded is initialized as null
-        if (mPanelExpanded == null || !mPanelExpanded.equals(isExpanded)) {
-            if (DEBUG) {
-                Log.i(TAG, "onPanelExpandedChanged: new=" + isExpanded);
-            }
-            mPanelExpanded = isExpanded;
-            synchronized (mDozingLock) {
-                maybeUpdateLoggingStatus();
-            }
-        }
-    }
-
-    @VisibleForTesting
     void onChildLocationsChanged() {
         if (mHandler.hasCallbacks(mVisibilityReporter)) {
             // Visibilities will be reported when the existing
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 d92d11b..c02382d 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
@@ -74,7 +74,6 @@
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.CallLayout;
 import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.flags.ViewRefactorFlag;
@@ -245,7 +244,6 @@
     private NotificationEntry mEntry;
     private String mAppName;
     private FalsingManager mFalsingManager;
-    private FalsingCollector mFalsingCollector;
 
     /**
      * Whether or not the notification is using the heads up view and should peek from the top.
@@ -1711,7 +1709,6 @@
             OnExpandClickListener onExpandClickListener,
             CoordinateOnClickListener onFeedbackClickListener,
             FalsingManager falsingManager,
-            FalsingCollector falsingCollector,
             StatusBarStateController statusBarStateController,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             OnUserInteractionCallback onUserInteractionCallback,
@@ -1743,7 +1740,6 @@
         mOnExpandClickListener = onExpandClickListener;
         setOnFeedbackClickListener(onFeedbackClickListener);
         mFalsingManager = falsingManager;
-        mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         for (NotificationContentView l : mLayouts) {
@@ -2471,7 +2467,6 @@
      * @param allowChildExpansion whether a call to this method allows expanding children
      */
     public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
-        mFalsingCollector.setNotificationExpanded();
         if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
                 && !mChildrenContainer.showingAsLowPriority()) {
             final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 80f5d19..af55f44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -34,7 +34,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.FalsingManager;
@@ -102,7 +101,6 @@
     private final NotificationGutsManager mNotificationGutsManager;
     private final OnUserInteractionCallback mOnUserInteractionCallback;
     private final FalsingManager mFalsingManager;
-    private final FalsingCollector mFalsingCollector;
     private final FeatureFlags mFeatureFlags;
     private final boolean mAllowLongPress;
     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@@ -222,7 +220,6 @@
             @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
             OnUserInteractionCallback onUserInteractionCallback,
             FalsingManager falsingManager,
-            FalsingCollector falsingCollector,
             FeatureFlags featureFlags,
             PeopleNotificationIdentifier peopleNotificationIdentifier,
             Optional<BubblesManager> bubblesManagerOptional,
@@ -251,7 +248,6 @@
         mFalsingManager = falsingManager;
         mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
         mAllowLongPress = allowLongPress;
-        mFalsingCollector = falsingCollector;
         mFeatureFlags = featureFlags;
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
         mBubblesManagerOptional = bubblesManagerOptional;
@@ -285,7 +281,6 @@
                 mOnExpandClickListener,
                 mOnFeedbackClickListener,
                 mFalsingManager,
-                mFalsingCollector,
                 mStatusBarStateController,
                 mPeopleNotificationIdentifier,
                 mOnUserInteractionCallback,
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 86f545d..f805183 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
@@ -80,6 +80,7 @@
     private final Executor mBgExecutor;
     private final SmartReplyStateInflater mSmartReplyStateInflater;
     private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+    private final NotificationContentInflaterLogger mLogger;
 
     @Inject
     NotificationContentInflater(
@@ -89,7 +90,8 @@
             MediaFeatureFlag mediaFeatureFlag,
             @Background Executor bgExecutor,
             SmartReplyStateInflater smartRepliesInflater,
-            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) {
+            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+            NotificationContentInflaterLogger logger) {
         mRemoteViewCache = remoteViewCache;
         mRemoteInputManager = remoteInputManager;
         mConversationProcessor = conversationProcessor;
@@ -97,6 +99,7 @@
         mBgExecutor = bgExecutor;
         mSmartReplyStateInflater = smartRepliesInflater;
         mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+        mLogger = logger;
     }
 
     @Override
@@ -111,9 +114,12 @@
             // We don't want to reinflate anything for removed notifications. Otherwise views might
             // be readded to the stack, leading to leaks. This may happen with low-priority groups
             // where the removal of already removed children can lead to a reinflation.
+            mLogger.logNotBindingRowWasRemoved(entry);
             return;
         }
 
+        mLogger.logBinding(entry, contentToBind);
+
         StatusBarNotification sbn = entry.getSbn();
 
         // To check if the notification has inline image and preload inline image if necessary.
@@ -141,7 +147,8 @@
                 mRemoteInputManager.getRemoteViewsOnClickHandler(),
                 mIsMediaInQS,
                 mSmartReplyStateInflater,
-                mNotifLayoutInflaterFactoryProvider);
+                mNotifLayoutInflaterFactoryProvider,
+                mLogger);
         if (mInflateSynchronously) {
             task.onPostExecute(task.doInBackground());
         } else {
@@ -166,12 +173,11 @@
                 bindParams.usesIncreasedHeadsUpHeight,
                 packageContext,
                 row,
-                mNotifLayoutInflaterFactoryProvider);
+                mNotifLayoutInflaterFactoryProvider,
+                mLogger);
 
-        result = inflateSmartReplyViews(result, reInflateFlags, entry,
-                row.getContext(), packageContext,
-                row.getExistingSmartReplyState(),
-                smartRepliesInflater);
+        result = inflateSmartReplyViews(result, reInflateFlags, entry, row.getContext(),
+                packageContext, row.getExistingSmartReplyState(), smartRepliesInflater, mLogger);
 
         apply(
                 mBgExecutor,
@@ -182,15 +188,20 @@
                 entry,
                 row,
                 mRemoteInputManager.getRemoteViewsOnClickHandler(),
-                null);
+                null /* callback */,
+                mLogger);
         return result;
     }
 
     @Override
-    public void cancelBind(
+    public boolean cancelBind(
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row) {
-        entry.abortTask();
+        final boolean abortedTask = entry.abortTask();
+        if (abortedTask) {
+            mLogger.logCancelBindAbortedTask(entry);
+        }
+        return abortedTask;
     }
 
     @Override
@@ -198,6 +209,7 @@
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row,
             @InflationFlag int contentToUnbind) {
+        mLogger.logUnbinding(entry, contentToUnbind);
         int curFlag = 1;
         while (contentToUnbind != 0) {
             if ((contentToUnbind & curFlag) != 0) {
@@ -279,7 +291,8 @@
             Context context,
             Context packageContext,
             InflatedSmartReplyState previousSmartReplyState,
-            SmartReplyStateInflater inflater) {
+            SmartReplyStateInflater inflater,
+            NotificationContentInflaterLogger logger) {
         boolean inflateContracted = (reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0
                 && result.newContentView != null;
         boolean inflateExpanded = (reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0
@@ -287,14 +300,17 @@
         boolean inflateHeadsUp = (reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0
                 && result.newHeadsUpView != null;
         if (inflateContracted || inflateExpanded || inflateHeadsUp) {
+            logger.logAsyncTaskProgress(entry, "inflating contracted smart reply state");
             result.inflatedSmartReplyState = inflater.inflateSmartReplyState(entry);
         }
         if (inflateExpanded) {
+            logger.logAsyncTaskProgress(entry, "inflating expanded smart reply state");
             result.expandedInflatedSmartReplies = inflater.inflateSmartReplyViewHolder(
                     context, packageContext, entry, previousSmartReplyState,
                     result.inflatedSmartReplyState);
         }
         if (inflateHeadsUp) {
+            logger.logAsyncTaskProgress(entry, "inflating heads up smart reply state");
             result.headsUpInflatedSmartReplies = inflater.inflateSmartReplyViewHolder(
                     context, packageContext, entry, previousSmartReplyState,
                     result.inflatedSmartReplyState);
@@ -306,22 +322,28 @@
             Notification.Builder builder, boolean isLowPriority, boolean usesIncreasedHeight,
             boolean usesIncreasedHeadsUpHeight, Context packageContext,
             ExpandableNotificationRow row,
-            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) {
+            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+            NotificationContentInflaterLogger logger) {
         InflationProgress result = new InflationProgress();
+        final NotificationEntry entryForLogging = row.getEntry();
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating contracted remote view");
             result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating expanded remote view");
             result.newExpandedView = createExpandedView(builder, isLowPriority);
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating heads up remote view");
             result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating public remote view");
             result.newPublicView = builder.makePublicContentView(isLowPriority);
         }
         setNotifsViewsInflaterFactory(result, row, notifLayoutInflaterFactoryProvider);
@@ -361,7 +383,8 @@
             NotificationEntry entry,
             ExpandableNotificationRow row,
             RemoteViews.InteractionHandler remoteViewClickHandler,
-            @Nullable InflationCallback callback) {
+            @Nullable InflationCallback callback,
+            NotificationContentInflaterLogger logger) {
         NotificationContentView privateLayout = row.getPrivateLayout();
         NotificationContentView publicLayout = row.getPublicLayout();
         final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();
@@ -374,6 +397,7 @@
             ApplyCallback applyCallback = new ApplyCallback() {
                 @Override
                 public void setResultView(View v) {
+                    logger.logAsyncTaskProgress(entry, "contracted view applied");
                     result.inflatedContentView = v;
                 }
                 @Override
@@ -381,12 +405,13 @@
                     return result.newContentView;
                 }
             };
+            logger.logAsyncTaskProgress(entry, "applying contracted view");
             applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                     remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
                     privateLayout, privateLayout.getContractedChild(),
                     privateLayout.getVisibleWrapper(
                             NotificationContentView.VISIBLE_TYPE_CONTRACTED),
-                    runningInflations, applyCallback);
+                    runningInflations, applyCallback, logger);
         }
 
         flag = FLAG_CONTENT_VIEW_EXPANDED;
@@ -398,6 +423,7 @@
                 ApplyCallback applyCallback = new ApplyCallback() {
                     @Override
                     public void setResultView(View v) {
+                        logger.logAsyncTaskProgress(entry, "expanded view applied");
                         result.inflatedExpandedView = v;
                     }
 
@@ -406,12 +432,13 @@
                         return result.newExpandedView;
                     }
                 };
+                logger.logAsyncTaskProgress(entry, "applying expanded view");
                 applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                         remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
                         callback, privateLayout, privateLayout.getExpandedChild(),
                         privateLayout.getVisibleWrapper(
                                 NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
-                        applyCallback);
+                        applyCallback, logger);
             }
         }
 
@@ -424,6 +451,7 @@
                 ApplyCallback applyCallback = new ApplyCallback() {
                     @Override
                     public void setResultView(View v) {
+                        logger.logAsyncTaskProgress(entry, "heads up view applied");
                         result.inflatedHeadsUpView = v;
                     }
 
@@ -432,12 +460,13 @@
                         return result.newHeadsUpView;
                     }
                 };
+                logger.logAsyncTaskProgress(entry, "applying heads up view");
                 applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                         remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
                         callback, privateLayout, privateLayout.getHeadsUpChild(),
                         privateLayout.getVisibleWrapper(
                                 VISIBLE_TYPE_HEADSUP), runningInflations,
-                        applyCallback);
+                        applyCallback, logger);
             }
         }
 
@@ -449,6 +478,7 @@
             ApplyCallback applyCallback = new ApplyCallback() {
                 @Override
                 public void setResultView(View v) {
+                    logger.logAsyncTaskProgress(entry, "public view applied");
                     result.inflatedPublicView = v;
                 }
 
@@ -457,19 +487,23 @@
                     return result.newPublicView;
                 }
             };
+            logger.logAsyncTaskProgress(entry, "applying public view");
             applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                     remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
                     publicLayout, publicLayout.getContractedChild(),
                     publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
-                    runningInflations, applyCallback);
+                    runningInflations, applyCallback, logger);
         }
 
         // Let's try to finish, maybe nobody is even inflating anything
         finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry,
-                row);
+                row, logger);
         CancellationSignal cancellationSignal = new CancellationSignal();
         cancellationSignal.setOnCancelListener(
-                () -> runningInflations.values().forEach(CancellationSignal::cancel));
+                () -> {
+                    logger.logAsyncTaskProgress(entry, "apply cancelled");
+                    runningInflations.values().forEach(CancellationSignal::cancel);
+                });
 
         return cancellationSignal;
     }
@@ -491,7 +525,8 @@
             View existingView,
             NotificationViewWrapper existingWrapper,
             final HashMap<Integer, CancellationSignal> runningInflations,
-            ApplyCallback applyCallback) {
+            ApplyCallback applyCallback,
+            NotificationContentInflaterLogger logger) {
         RemoteViews newContentView = applyCallback.getRemoteView();
         if (inflateSynchronously) {
             try {
@@ -511,7 +546,8 @@
                     existingWrapper.onReinflated();
                 }
             } catch (Exception e) {
-                handleInflationError(runningInflations, e, row.getEntry(), callback);
+                handleInflationError(runningInflations, e, row.getEntry(), callback, logger,
+                        "applying view synchronously");
                 // Add a running inflation to make sure we don't trigger callbacks.
                 // Safe to do because only happens in tests.
                 runningInflations.put(inflationId, new CancellationSignal());
@@ -532,7 +568,7 @@
                 String invalidReason = isValidView(v, entry, row.getResources());
                 if (invalidReason != null) {
                     handleInflationError(runningInflations, new InflationException(invalidReason),
-                            row.getEntry(), callback);
+                            row.getEntry(), callback, logger, "applied invalid view");
                     runningInflations.remove(inflationId);
                     return;
                 }
@@ -543,7 +579,7 @@
                 }
                 runningInflations.remove(inflationId);
                 finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations,
-                        callback, entry, row);
+                        callback, entry, row, logger);
             }
 
             @Override
@@ -569,7 +605,7 @@
                 } catch (Exception anotherException) {
                     runningInflations.remove(inflationId);
                     handleInflationError(runningInflations, e, row.getEntry(),
-                            callback);
+                            callback, logger, "applying view");
                 }
             }
         };
@@ -653,8 +689,10 @@
 
     private static void handleInflationError(
             HashMap<Integer, CancellationSignal> runningInflations, Exception e,
-            NotificationEntry notification, @Nullable InflationCallback callback) {
+            NotificationEntry notification, @Nullable InflationCallback callback,
+            NotificationContentInflaterLogger logger, String logContext) {
         Assert.isMainThread();
+        logger.logAsyncTaskException(notification, logContext, e);
         runningInflations.values().forEach(CancellationSignal::cancel);
         if (callback != null) {
             callback.handleInflationException(notification, e);
@@ -670,11 +708,12 @@
             @InflationFlag int reInflateFlags, NotifRemoteViewCache remoteViewCache,
             HashMap<Integer, CancellationSignal> runningInflations,
             @Nullable InflationCallback endListener, NotificationEntry entry,
-            ExpandableNotificationRow row) {
+            ExpandableNotificationRow row, NotificationContentInflaterLogger logger) {
         Assert.isMainThread();
         NotificationContentView privateLayout = row.getPrivateLayout();
         NotificationContentView publicLayout = row.getPublicLayout();
         if (runningInflations.isEmpty()) {
+            logger.logAsyncTaskProgress(entry, "finishing");
             boolean setRepliesAndActions = true;
             if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
                 if (result.inflatedContentView != null) {
@@ -828,6 +867,7 @@
         private final boolean mIsMediaInQS;
         private final SmartReplyStateInflater mSmartRepliesInflater;
         private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+        private final NotificationContentInflaterLogger mLogger;
 
         private AsyncInflationTask(
                 Executor bgExecutor,
@@ -844,7 +884,8 @@
                 RemoteViews.InteractionHandler remoteViewClickHandler,
                 boolean isMediaFlagEnabled,
                 SmartReplyStateInflater smartRepliesInflater,
-                NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) {
+                NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+                NotificationContentInflaterLogger logger) {
             mEntry = entry;
             mRow = row;
             mBgExecutor = bgExecutor;
@@ -861,6 +902,7 @@
             mConversationProcessor = conversationProcessor;
             mIsMediaInQS = isMediaFlagEnabled;
             mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+            mLogger = logger;
             entry.setInflationTask(this);
         }
 
@@ -900,13 +942,16 @@
                     packageContext = new RtlEnabledContext(packageContext);
                 }
                 if (mEntry.getRanking().isConversation()) {
-                    mConversationProcessor.processNotification(mEntry, recoveredBuilder);
+                    mConversationProcessor.processNotification(mEntry, recoveredBuilder, mLogger);
                 }
                 InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
                         recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
                         mUsesIncreasedHeadsUpHeight, packageContext, mRow,
-                        mNotifLayoutInflaterFactoryProvider);
+                        mNotifLayoutInflaterFactoryProvider, mLogger);
+                mLogger.logAsyncTaskProgress(mEntry,
+                        "getting existing smart reply state (on wrong thread!)");
                 InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
+                mLogger.logAsyncTaskProgress(mEntry, "inflating smart reply views");
                 InflationProgress result = inflateSmartReplyViews(
                         inflationProgress,
                         mReInflateFlags,
@@ -914,14 +959,20 @@
                         mContext,
                         packageContext,
                         previousSmartReplyState,
-                        mSmartRepliesInflater);
+                        mSmartRepliesInflater,
+                        mLogger);
 
+                mLogger.logAsyncTaskProgress(mEntry,
+                        "getting row image resolver (on wrong thread!)");
+                final NotificationInlineImageResolver imageResolver = mRow.getImageResolver();
                 // wait for image resolver to finish preloading
-                mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
+                mLogger.logAsyncTaskProgress(mEntry, "waiting for preloaded images");
+                imageResolver.waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
 
                 return result;
             } catch (Exception e) {
                 mError = e;
+                mLogger.logAsyncTaskException(mEntry, "inflating", e);
                 return null;
             }
         }
@@ -929,6 +980,7 @@
         @Override
         protected void onPostExecute(InflationProgress result) {
             if (mError == null) {
+                // Logged in detail in apply.
                 mCancellationSignal = apply(
                         mBgExecutor,
                         mInflateSynchronously,
@@ -938,7 +990,8 @@
                         mEntry,
                         mRow,
                         mRemoteViewClickHandler,
-                        this);
+                        this /* callback */,
+                        mLogger);
             } else {
                 handleError(mError);
             }
@@ -961,10 +1014,13 @@
 
         @Override
         public void abort() {
+            mLogger.logAsyncTaskProgress(mEntry, "cancelling inflate");
             cancel(true /* mayInterruptIfRunning */);
             if (mCancellationSignal != null) {
+                mLogger.logAsyncTaskProgress(mEntry, "cancelling apply");
                 mCancellationSignal.cancel();
             }
+            mLogger.logAsyncTaskProgress(mEntry, "aborted");
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
new file mode 100644
index 0000000..4f5455d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
+import javax.inject.Inject
+
+class NotificationContentInflaterLogger
+@Inject
+constructor(@NotifInflationLog private val buffer: LogBuffer) {
+    fun logNotBindingRowWasRemoved(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = entry.logKey },
+            { "not inflating $str1: row was removed" }
+        )
+    }
+
+    fun logBinding(entry: NotificationEntry, @InflationFlag flag: Int) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                int1 = flag
+            },
+            { "binding views ${flagToString(int1)} for $str1" }
+        )
+    }
+
+    fun logCancelBindAbortedTask(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = entry.logKey },
+            { "aborted task to cancel binding $str1" }
+        )
+    }
+
+    fun logUnbinding(entry: NotificationEntry, @InflationFlag flag: Int) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                int1 = flag
+            },
+            { "unbinding views ${flagToString(int1)} for $str1" }
+        )
+    }
+
+    fun logAsyncTaskProgress(entry: NotificationEntry, progress: String) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = progress
+            },
+            { "async task for $str1: $str2" }
+        )
+    }
+
+    fun logAsyncTaskException(entry: NotificationEntry, logContext: String, exception: Throwable) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = logContext
+                str3 = exception.stackTraceToString()
+            },
+            { "async task for $str1 got exception $str2: $str3" }
+        )
+    }
+
+    companion object {
+        fun flagToString(@InflationFlag flag: Int): String {
+            if (flag == 0) {
+                return "NONE"
+            }
+            if (flag == FLAG_CONTENT_VIEW_ALL) {
+                return "ALL"
+            }
+
+            var l = mutableListOf<String>()
+            if (flag and FLAG_CONTENT_VIEW_CONTRACTED != 0) {
+                l.add("CONTRACTED")
+            }
+            if (flag and FLAG_CONTENT_VIEW_EXPANDED != 0) {
+                l.add("EXPANDED")
+            }
+            if (flag and FLAG_CONTENT_VIEW_HEADS_UP != 0) {
+                l.add("HEADS_UP")
+            }
+            if (flag and FLAG_CONTENT_VIEW_PUBLIC != 0) {
+                l.add("PUBLIC")
+            }
+            return l.joinToString("|")
+        }
+    }
+}
+
+private const val TAG = "NotificationContentInflater"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 6f79ea8..44ead26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -45,6 +45,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settingslib.notification.ConversationIconFactory;
+import com.android.systemui.CoreStartable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -53,6 +54,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -69,6 +71,7 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.wmshell.BubblesManager;
 
 import java.util.Optional;
@@ -80,7 +83,7 @@
  * closing guts, and keeping track of the currently exposed notification guts.
  */
 @SysUISingleton
-public class NotificationGutsManager implements NotifGutsViewManager {
+public class NotificationGutsManager implements NotifGutsViewManager, CoreStartable {
     private static final String TAG = "NotificationGutsManager";
 
     // Must match constant in Settings. Used to highlight preferences when linking to Settings.
@@ -109,6 +112,7 @@
 
     private final Handler mMainHandler;
     private final Handler mBgHandler;
+    private final JavaAdapter mJavaAdapter;
     private final Optional<BubblesManager> mBubblesManagerOptional;
     private Runnable mOpenRunnable;
     private final INotificationManager mNotificationManager;
@@ -121,6 +125,7 @@
     private final UserContextProvider mContextTracker;
     private final UiEventLogger mUiEventLogger;
     private final ShadeController mShadeController;
+    private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
     private NotifGutsViewListener mGutsListener;
     private final HeadsUpManagerPhone mHeadsUpManagerPhone;
     private final ActivityStarter mActivityStarter;
@@ -129,6 +134,7 @@
     public NotificationGutsManager(Context context,
             @Main Handler mainHandler,
             @Background Handler bgHandler,
+            JavaAdapter javaAdapter,
             AccessibilityManager accessibilityManager,
             HighPriorityProvider highPriorityProvider,
             INotificationManager notificationManager,
@@ -143,6 +149,7 @@
             UiEventLogger uiEventLogger,
             OnUserInteractionCallback onUserInteractionCallback,
             ShadeController shadeController,
+            WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             StatusBarStateController statusBarStateController,
             DeviceProvisionedController deviceProvisionedController,
@@ -152,6 +159,7 @@
         mContext = context;
         mMainHandler = mainHandler;
         mBgHandler = bgHandler;
+        mJavaAdapter = javaAdapter;
         mAccessibilityManager = accessibilityManager;
         mHighPriorityProvider = highPriorityProvider;
         mNotificationManager = notificationManager;
@@ -166,6 +174,7 @@
         mUiEventLogger = uiEventLogger;
         mOnUserInteractionCallback = onUserInteractionCallback;
         mShadeController = shadeController;
+        mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
         mLockscreenUserManager = notificationLockscreenUserManager;
         mStatusBarStateController = statusBarStateController;
         mDeviceProvisionedController = deviceProvisionedController;
@@ -187,6 +196,25 @@
         mNotificationActivityStarter = notificationActivityStarter;
     }
 
+    @Override
+    public void start() {
+        mJavaAdapter.alwaysCollectFlow(
+                mWindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible(),
+                this::onLockscreenShadeVisibilityChanged);
+    }
+
+    private void onLockscreenShadeVisibilityChanged(boolean visible) {
+        if (!visible) {
+            closeAndSaveGuts(
+                    /* removeLeavebehind= */ true ,
+                    /* force= */ true,
+                    /* removeControls= */ true,
+                    /* x= */ -1,
+                    /* y= */ -1,
+                    /* resetMenu= */ true);
+        }
+    }
+
     public void onDensityOrFontScaleChanged(NotificationEntry entry) {
         setExposedGuts(entry.getGuts());
         bindGuts(entry.getRow());
@@ -512,7 +540,7 @@
             mNotificationGutsExposed.removeCallbacks(mOpenRunnable);
             mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force);
         }
-        if (resetMenu) {
+        if (resetMenu && mListContainer != null) {
             mListContainer.resetExposedMenuView(false /* animate */, true /* force */);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index a9f83c8..d7b7aa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -54,8 +54,9 @@
      *
      * @param entry notification
      * @param row notification row to cancel bind on
+     * @return true if an on-going bind operation was cancelled
      */
-    void cancelBind(
+    boolean cancelBind(
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index 81cf146..b70da00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -57,7 +57,7 @@
             @NonNull StageCallback callback) {
         RowContentBindParams params = getStageParams(entry);
 
-        mLogger.logStageParams(entry, params);
+        mLogger.logExecutingStage(entry, params);
 
         // Resolve content to bind/unbind.
         @InflationFlag int inflationFlags = params.getContentViews();
@@ -96,7 +96,10 @@
     protected void abortStage(
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row) {
-        mBinder.cancelBind(entry, row);
+        final boolean cancelledBind = mBinder.cancelBind(entry, row);
+        if (cancelledBind) {
+            mLogger.logAbortStageCancelledBind(entry);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
index 02627fd..1b961cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
@@ -16,22 +16,30 @@
 
 package com.android.systemui.statusbar.notification.row
 
-import com.android.systemui.log.dagger.NotificationLog
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.dagger.NotifInflationLog
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.logKey
 import javax.inject.Inject
 
 class RowContentBindStageLogger @Inject constructor(
-    @NotificationLog private val buffer: LogBuffer
+    @NotifInflationLog private val buffer: LogBuffer
 ) {
-    fun logStageParams(entry: NotificationEntry, stageParams: RowContentBindParams) {
+    fun logExecutingStage(entry: NotificationEntry, stageParams: RowContentBindParams) {
         buffer.log(TAG, INFO, {
             str1 = entry.logKey
             str2 = stageParams.toString()
         }, {
-            "Invalidated notif $str1 with params: $str2"
+            "executing bind stage for $str1 with params $str2"
+        })
+    }
+
+    fun logAbortStageCancelledBind(entry: NotificationEntry) {
+        buffer.log(TAG, INFO, {
+            str1 = entry.logKey
+        }, {
+            "cancelled bind to abort stage for $str1"
         })
     }
 }
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 6db8df9..d8f513c 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
@@ -455,7 +455,6 @@
 
                 @Override
                 public void onDragCancelled(View v) {
-                    mFalsingCollector.onNotificationStopDismissing();
                 }
 
                 /**
@@ -501,7 +500,6 @@
                     }
 
                     mView.addSwipedOutView(view);
-                    mFalsingCollector.onNotificationDismissed();
                     if (mFalsingCollector.shouldEnforceBouncer()) {
                         mActivityStarter.executeRunnableDismissingKeyguard(
                                 null,
@@ -549,7 +547,6 @@
 
                 @Override
                 public void onBeginDrag(View v) {
-                    mFalsingCollector.onNotificationStartDismissing();
                     mView.onSwipeBegin(v);
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index d0a093c..67c0c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -44,7 +44,6 @@
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
-import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.util.Compile;
 
@@ -183,8 +182,6 @@
         return contextForUser.getPackageManager();
     }
 
-    void start();
-
     boolean updateIsKeyguard();
 
     boolean updateIsKeyguard(boolean forceStateChange);
@@ -200,14 +197,6 @@
 
     void onKeyguardViewManagerStatesUpdated();
 
-    boolean isPulsing();
-
-    boolean isOccluded();
-
-    boolean isDeviceInVrMode();
-
-    NotificationPresenter getPresenter();
-
     /**
      * Used to dispatch initial touch events before crossing the threshold to pull down the
      * notification shade. After that, since the launcher window is set to slippery, input
@@ -226,8 +215,6 @@
     /** */
     boolean getCommandQueuePanelsEnabled();
 
-    BiometricUnlockController getBiometricUnlockController();
-
     void showWirelessChargingAnimation(int batteryLevel);
 
     void checkBarModes();
@@ -236,9 +223,6 @@
 
     void setInteracting(int barWindow, boolean interacting);
 
-    @Override
-    void dump(PrintWriter pwOriginal, String[] args);
-
     /** @deprecated Use {@link DisplayMetricsRepository} instead. */
     @Deprecated
     float getDisplayWidth();
@@ -247,8 +231,6 @@
     @Deprecated
     float getDisplayHeight();
 
-    void readyForKeyguardDone();
-
     void showKeyguard();
 
     boolean hideKeyguard();
@@ -289,8 +271,6 @@
 
     void setBouncerShowing(boolean bouncerShowing);
 
-    int getWakefulnessState();
-
     boolean isScreenFullyOff();
 
     void showScreenPinningRequest(int taskId, boolean allowCancel);
@@ -331,8 +311,6 @@
 
     boolean isBouncerShowingOverDream();
 
-    boolean isKeyguardSecure();
-
     void updateNotificationPanelTouchState();
 
     int getRotation();
@@ -370,8 +348,6 @@
     @Deprecated
     float getDisplayDensity();
 
-    void extendDozePulse();
-
     public static class KeyboardShortcutsMessage {
         final int mDeviceId;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
new file mode 100644
index 0000000..98ba6d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.content.Intent
+import androidx.lifecycle.LifecycleRegistry
+import com.android.keyguard.AuthKeyguardMessageArea
+import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.navigationbar.NavigationBarView
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
+import com.android.systemui.qs.QSPanelController
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+
+/**
+ * Empty implementation of [CentralSurfaces] for variants only need to override portions of the
+ * interface.
+ *
+ * **Important**: Prefer binding an Optional<CentralSurfaces> to an empty optional instead of
+ * including this class.
+ */
+abstract class CentralSurfacesEmptyImpl : CentralSurfaces {
+    override val lifecycle = LifecycleRegistry(this)
+    override fun updateIsKeyguard() = false
+    override fun updateIsKeyguard(forceStateChange: Boolean) = false
+    override fun getKeyguardMessageArea(): AuthKeyguardMessageArea? = null
+    override fun isLaunchingActivityOverLockscreen() = false
+    override fun onKeyguardViewManagerStatesUpdated() {}
+    override fun onInputFocusTransfer(start: Boolean, cancel: Boolean, velocity: Float) {}
+    override fun getCommandQueuePanelsEnabled() = false
+    override fun showWirelessChargingAnimation(batteryLevel: Int) {}
+    override fun checkBarModes() {}
+    override fun updateBubblesVisibility() {}
+    override fun setInteracting(barWindow: Int, interacting: Boolean) {}
+    override fun getDisplayWidth() = 0f
+    override fun getDisplayHeight() = 0f
+    override fun showKeyguard() {}
+    override fun hideKeyguard() = false
+    override fun showKeyguardImpl() {}
+    override fun fadeKeyguardAfterLaunchTransition(
+        beforeFading: Runnable?,
+        endRunnable: Runnable?,
+        cancelRunnable: Runnable?,
+    ) {}
+    override fun startLaunchTransitionTimeout() {}
+    override fun hideKeyguardImpl(forceStateChange: Boolean) = false
+    override fun keyguardGoingAway() {}
+    override fun setKeyguardFadingAway(startTime: Long, delay: Long, fadeoutDuration: Long) {}
+    override fun finishKeyguardFadingAway() {}
+    override fun userActivity() {}
+    override fun endAffordanceLaunch() {}
+    override fun shouldKeyguardHideImmediately() = false
+    override fun showBouncerWithDimissAndCancelIfKeyguard(
+        performAction: OnDismissAction?,
+        cancelAction: Runnable?,
+    ) {}
+    override fun getNavigationBarView(): NavigationBarView? = null
+    override fun isOverviewEnabled() = false
+    override fun showPinningEnterExitToast(entering: Boolean) {}
+    override fun showPinningEscapeToast() {}
+    override fun setBouncerShowing(bouncerShowing: Boolean) {}
+    override fun isScreenFullyOff() = false
+    override fun showScreenPinningRequest(taskId: Int, allowCancel: Boolean) {}
+    override fun getEmergencyActionIntent(): Intent? = null
+    override fun isCameraAllowedByAdmin() = false
+    override fun isGoingToSleep() = false
+    override fun notifyBiometricAuthModeChanged() {}
+    override fun setTransitionToFullShadeProgress(transitionToFullShadeProgress: Float) {}
+    override fun setPrimaryBouncerHiddenFraction(expansion: Float) {}
+    override fun updateScrimController() {}
+    override fun isKeyguardShowing() = false
+    override fun shouldIgnoreTouch() = false
+    override fun isDeviceInteractive() = false
+    override fun awakenDreams() {}
+    override fun clearNotificationEffects() {}
+    override fun isBouncerShowing() = false
+    override fun isBouncerShowingScrimmed() = false
+    override fun isBouncerShowingOverDream() = false
+    override fun updateNotificationPanelTouchState() {}
+    override fun getRotation() = 0
+    override fun setBarStateForTest(state: Int) {}
+    override fun showTransientUnchecked() {}
+    override fun clearTransient() {}
+    override fun acquireGestureWakeLock(time: Long) {}
+    override fun setAppearance(appearance: Int) = false
+    override fun getBarMode() = 0
+    override fun resendMessage(msg: Int) {}
+    override fun resendMessage(msg: Any?) {}
+    override fun setLastCameraLaunchSource(source: Int) {}
+    override fun setLaunchCameraOnFinishedGoingToSleep(launch: Boolean) {}
+    override fun setLaunchCameraOnFinishedWaking(launch: Boolean) {}
+    override fun setLaunchEmergencyActionOnFinishedGoingToSleep(launch: Boolean) {}
+    override fun setLaunchEmergencyActionOnFinishedWaking(launch: Boolean) {}
+    override fun getQSPanelController(): QSPanelController? = null
+    override fun getDisplayDensity() = 0f
+    override fun setIsLaunchingActivityOverLockscreen(isLaunchingActivityOverLockscreen: Boolean) {}
+    override fun getAnimatorControllerFromNotification(
+        associatedView: ExpandableNotificationRow?,
+    ): ActivityLaunchAnimator.Controller? = null
+}
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 4aa8b6b..b797c63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -92,17 +92,12 @@
 import android.view.MotionEvent;
 import android.view.ThreadedRenderer;
 import android.view.View;
-import android.view.ViewRootImpl;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.DateTimeView;
-import android.window.BackEvent;
-import android.window.OnBackAnimationCallback;
-import android.window.OnBackInvokedCallback;
-import android.window.OnBackInvokedDispatcher;
 
 import androidx.annotation.NonNull;
 import androidx.lifecycle.Lifecycle;
@@ -176,6 +171,7 @@
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.settings.brightness.BrightnessSliderController;
@@ -221,15 +217,12 @@
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
 import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -459,9 +452,9 @@
             mNotificationShadeWindowViewControllerLazy;
     private final DozeParameters mDozeParameters;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
-    private final CentralSurfacesComponent.Factory mCentralSurfacesComponentFactory;
     private final PluginManager mPluginManager;
     private final ShadeController mShadeController;
+    private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
     private final InitController mInitController;
     private final Lazy<CameraLauncher> mCameraLauncherLazy;
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
@@ -489,13 +482,11 @@
     private View mReportRejectedTouch;
 
     private final NotificationGutsManager mGutsManager;
-    private final NotificationLogger mNotificationLogger;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
     private final KeyguardViewMediator mKeyguardViewMediator;
     protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private final BrightnessSliderController.Factory mBrightnessSliderFactory;
     private final FeatureFlags mFeatureFlags;
-    private final boolean mAnimateBack;
     private final FragmentService mFragmentService;
     private final ScreenOffAnimationController mScreenOffAnimationController;
     private final WallpaperController mWallpaperController;
@@ -506,15 +497,6 @@
     private final Provider<FingerprintManager> mFingerprintManager;
     private final ActivityStarter mActivityStarter;
 
-    private CentralSurfacesComponent mCentralSurfacesComponent;
-
-    /**
-     * This keeps track of whether we have (or haven't) registered the predictive back callback.
-     * Since we can have visible -> visible transitions, we need to avoid
-     * double-registering (or double-unregistering) our callback.
-     */
-    private boolean mIsBackCallbackRegistered = false;
-
     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
 
@@ -624,8 +606,8 @@
 
     private final ActivityLaunchAnimator mActivityLaunchAnimator;
     private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
-    private final NotificationPresenter mPresenter;
-    private final NotificationActivityStarter mNotificationActivityStarter;
+    private final Lazy<NotificationPresenter> mPresenterLazy;
+    private final Lazy<NotificationActivityStarter> mNotificationActivityStarterLazy;
     private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
     private final Optional<Bubbles> mBubblesOptional;
     private final Lazy<NoteTaskController> mNoteTaskControllerLazy;
@@ -640,31 +622,6 @@
 
     private final InteractionJankMonitor mJankMonitor;
 
-    /** Existing callback that handles back gesture invoked for the Shade. */
-    private final OnBackInvokedCallback mOnBackInvokedCallback;
-
-    /**
-     *  New callback that handles back gesture invoked, cancel, progress
-     *  and provides feedback via Shade animation.
-     *  (enabled via the WM_SHADE_ANIMATE_BACK_GESTURE flag)
-     */
-    private final OnBackAnimationCallback mOnBackAnimationCallback = new OnBackAnimationCallback() {
-        @Override
-        public void onBackInvoked() {
-            mBackActionInteractor.onBackRequested();
-        }
-
-        @Override
-        public void onBackProgressed(BackEvent event) {
-            if (mBackActionInteractor.shouldBackBeHandled()) {
-                if (mShadeSurface.canBeCollapsed()) {
-                    float fraction = event.getProgress();
-                    mShadeSurface.onBackProgressed(fraction);
-                }
-            }
-        }
-    };
-
     /**
      * Public constructor for CentralSurfaces.
      *
@@ -694,7 +651,6 @@
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
             NotificationGutsManager notificationGutsManager,
-            NotificationLogger notificationLogger,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
             ShadeExpansionStateManager shadeExpansionStateManager,
             KeyguardViewMediator keyguardViewMediator,
@@ -725,8 +681,9 @@
             Lazy<NotificationShadeWindowViewController> notificationShadeWindowViewControllerLazy,
             NotificationShelfController notificationShelfController,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
-            NotificationPresenter notificationPresenter,
-            NotificationActivityStarter notificationActivityStarter,
+            // Lazys due to b/298099682.
+            Lazy<NotificationPresenter> notificationPresenterLazy,
+            Lazy<NotificationActivityStarter> notificationActivityStarterLazy,
             NotificationLaunchAnimatorControllerProvider notifLaunchAnimatorControllerProvider,
             NotificationExpansionRepository notificationExpansionRepository,
             DozeParameters dozeParameters,
@@ -741,10 +698,10 @@
             DozeScrimController dozeScrimController,
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
-            CentralSurfacesComponent.Factory centralSurfacesComponentFactory,
             Lazy<CentralSurfacesCommandQueueCallbacks> commandQueueCallbacksLazy,
             PluginManager pluginManager,
             ShadeController shadeController,
+            WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             ViewMediatorCallback viewMediatorCallback,
             InitController initController,
@@ -803,7 +760,6 @@
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
         mGutsManager = notificationGutsManager;
-        mNotificationLogger = notificationLogger;
         mNotificationInterruptStateProvider = notificationInterruptStateProvider;
         mShadeExpansionStateManager = shadeExpansionStateManager;
         mKeyguardViewMediator = keyguardViewMediator;
@@ -836,8 +792,8 @@
         mStackScrollerController = notificationStackScrollLayoutController;
         mStackScroller = mStackScrollerController.getView();
         mNotifListContainer = mStackScrollerController.getNotificationListContainer();
-        mPresenter = notificationPresenter;
-        mNotificationActivityStarter = notificationActivityStarter;
+        mPresenterLazy = notificationPresenterLazy;
+        mNotificationActivityStarterLazy = notificationActivityStarterLazy;
         mNotificationAnimationProvider = notifLaunchAnimatorControllerProvider;
         mNotificationExpansionRepository = notificationExpansionRepository;
         mDozeServiceHost = dozeServiceHost;
@@ -852,10 +808,10 @@
         mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
         mVolumeComponent = volumeComponent;
         mCommandQueue = commandQueue;
-        mCentralSurfacesComponentFactory = centralSurfacesComponentFactory;
         mCommandQueueCallbacksLazy = commandQueueCallbacksLazy;
         mPluginManager = pluginManager;
         mShadeController = shadeController;
+        mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mKeyguardViewMediatorCallback = viewMediatorCallback;
         mInitController = initController;
@@ -926,14 +882,6 @@
         if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI)) {
             mContext.getApplicationInfo().setEnableOnBackInvokedCallback(true);
         }
-        // Based on teamfood flag, enable predictive back animation for the Shade.
-        mAnimateBack = mFeatureFlags.isEnabled(Flags.WM_SHADE_ANIMATE_BACK_GESTURE);
-        mOnBackInvokedCallback = () -> {
-            if (DEBUG) {
-                Log.d(TAG, "mOnBackInvokedCallback() called");
-            }
-            mBackActionInteractor.onBackRequested();
-        };
     }
 
     private void initBubbles(Bubbles bubbles) {
@@ -1171,7 +1119,10 @@
                 new FoldStateListener(mContext, this::onFoldedStateChanged));
     }
 
-    @VisibleForTesting
+    /**
+     * @deprecated use {@link
+     * WindowRootViewVisibilityInteractor.isLockscreenOrShadeVisible} instead.
+     */    @VisibleForTesting
     void initShadeVisibilityListener() {
         mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {
             @Override
@@ -1236,10 +1187,15 @@
         updateResources();
         updateTheme();
 
-        inflateStatusBarWindow();
+        setUpShade();
         getNotificationShadeWindowView().setOnTouchListener(getStatusBarWindowTouchListener());
         mWallpaperController.setRootView(getNotificationShadeWindowView());
 
+        mDemoModeController.addCallback(mDemoModeCallback);
+
+        mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get();
+        mCommandQueue.addCallback(mCommandQueueCallbacks);
+
         // TODO: Deal with the ugliness that comes from having some of the status bar broken out
         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
         if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
@@ -1270,8 +1226,7 @@
                     setBouncerShowingForStatusBarComponents(mBouncerShowing);
                     checkBarModes();
                 });
-        mStatusBarInitializer.initializeStatusBar(
-                mCentralSurfacesComponent::createCollapsedStatusBarFragment);
+        mStatusBarInitializer.initializeStatusBar();
 
         mStatusBarTouchableRegionManager.setup(this, getNotificationShadeWindowView());
 
@@ -1480,7 +1435,7 @@
         // - Shade is in QQS over keyguard - swiping up should take us back to keyguard
         if (!isKeyguardShowing()
                 || mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
-                || isOccluded()
+                || mKeyguardStateController.isOccluded()
                 || !mKeyguardStateController.canDismissLockScreen()
                 || mKeyguardViewMediator.isAnySimPinSecure()
                 || (mQsController.getExpanded() && trackingTouch)
@@ -1555,14 +1510,16 @@
         mActivityLaunchAnimator.setCallback(mActivityLaunchAnimatorCallback);
         mActivityLaunchAnimator.addListener(mActivityLaunchAnimatorListener);
         mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
-        mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
-        mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
-        mShadeController.setNotificationPresenter(mPresenter);
+        mStackScrollerController.setNotificationActivityStarter(
+                mNotificationActivityStarterLazy.get());
+        mGutsManager.setNotificationActivityStarter(mNotificationActivityStarterLazy.get());
+        mShadeController.setNotificationPresenter(mPresenterLazy.get());
         mNotificationsController.initialize(
-                mPresenter,
+                mPresenterLazy.get(),
                 mNotifListContainer,
                 mStackScrollerController.getNotifStackController(),
-                mNotificationActivityStarter);
+                mNotificationActivityStarterLazy.get());
+        mWindowRootViewVisibilityInteractor.setUp(mPresenterLazy.get(), mNotificationsController);
     }
 
     /**
@@ -1593,15 +1550,7 @@
         };
     }
 
-    private void inflateStatusBarWindow() {
-        if (mCentralSurfacesComponent != null) {
-            Log.e(TAG, "CentralSurfacesComponent being recreated; this is unexpected.");
-        }
-        mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create();
-        mFragmentService.addFragmentInstantiationProvider(
-                CollapsedStatusBarFragment.class,
-                mCentralSurfacesComponent::createCollapsedStatusBarFragment);
-
+    private void setUpShade() {
         // Ideally, NotificationShadeWindowController could automatically fetch the window root view
         // in #attach or a CoreStartable.start method or something similar. But for now, to avoid
         // regressions, we'll continue standing up the root view in CentralSurfaces.
@@ -1610,12 +1559,6 @@
         mShadeController.setNotificationShadeWindowViewController(
                 getNotificationShadeWindowViewController());
         mBackActionInteractor.setup(mQsController, mShadeSurface);
-
-        // Listen for demo mode changes
-        mDemoModeController.addCallback(mDemoModeCallback);
-
-        mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get();
-        mCommandQueue.addCallback(mCommandQueueCallbacks);
     }
 
     protected NotificationShadeWindowViewController getNotificationShadeWindowViewController() {
@@ -1708,32 +1651,6 @@
         logStateToEventlog();
     }
 
-    @Override
-    public boolean isPulsing() {
-        return mDozeServiceHost.isPulsing();
-    }
-
-    /**
-     * When the keyguard is showing and covered by a "showWhenLocked" activity it
-     * is occluded. This is controlled by {@link com.android.server.policy.PhoneWindowManager}
-     *
-     * @return whether the keyguard is currently occluded
-     */
-    @Override
-    public boolean isOccluded() {
-        return mKeyguardStateController.isOccluded();
-    }
-
-    @Override
-    public boolean isDeviceInVrMode() {
-        return mPresenter.isDeviceInVrMode();
-    }
-
-    @Override
-    public NotificationPresenter getPresenter() {
-        return mPresenter;
-    }
-
     @VisibleForTesting
     @Override
     public void setBarStateForTest(int state) {
@@ -1795,7 +1712,7 @@
 
     private void onExpandedInvisible() {
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-        if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
+        if (!mNotificationActivityStarterLazy.get().isCollapsingToShowActivityOverLockscreen()) {
             showBouncerOrLockScreenIfKeyguard();
         } else if (DEBUG) {
             Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
@@ -1808,11 +1725,6 @@
     }
 
     @Override
-    public BiometricUnlockController getBiometricUnlockController() {
-        return mBiometricUnlockController;
-    }
-
-    @Override
     public void showTransientUnchecked() {
         if (!mTransientShown) {
             mTransientShown = true;
@@ -1963,8 +1875,6 @@
         pw.print("  mDozing="); pw.println(mDozing);
         pw.print("  mWallpaperSupported= "); pw.println(mWallpaperSupported);
 
-        pw.println("  ShadeWindowView: ");
-        getNotificationShadeWindowViewController().dump(pw, args);
         CentralSurfaces.dumpBarTransitions(
                 pw, "PhoneStatusBarTransitions", mStatusBarTransitions);
 
@@ -2077,11 +1987,6 @@
         return mDisplay.getRotation();
     }
 
-    @Override
-    public void readyForKeyguardDone() {
-        mStatusBarKeyguardViewManager.readyForKeyguardDone();
-    }
-
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -2133,7 +2038,7 @@
             String action = intent.getAction();
             if (ACTION_FAKE_ARTWORK.equals(action)) {
                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
-                    mPresenter.updateMediaMetaData(true, true);
+                    mPresenterLazy.get().updateMediaMetaData(true, true);
                 }
             }
         }
@@ -2170,82 +2075,6 @@
                 com.android.systemui.R.dimen.physical_power_button_center_screen_location_y));
     }
 
-    protected void handleVisibleToUserChanged(boolean visibleToUser) {
-        if (visibleToUser) {
-            onVisibleToUser();
-            mNotificationLogger.startNotificationLogging();
-
-            if (!mIsBackCallbackRegistered) {
-                ViewRootImpl viewRootImpl = getViewRootImpl();
-                if (viewRootImpl != null) {
-                    viewRootImpl.getOnBackInvokedDispatcher()
-                            .registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT,
-                                    mAnimateBack ? mOnBackAnimationCallback
-                                            : mOnBackInvokedCallback);
-                    mIsBackCallbackRegistered = true;
-                    if (DEBUG) Log.d(TAG, "is now VISIBLE to user AND callback registered");
-                }
-            } else {
-                if (DEBUG) Log.d(TAG, "is now VISIBLE to user, BUT callback ALREADY unregistered");
-            }
-        } else {
-            mNotificationLogger.stopNotificationLogging();
-            onInvisibleToUser();
-
-            if (mIsBackCallbackRegistered) {
-                ViewRootImpl viewRootImpl = getViewRootImpl();
-                if (viewRootImpl != null) {
-                    viewRootImpl.getOnBackInvokedDispatcher()
-                            .unregisterOnBackInvokedCallback(
-                                    mAnimateBack ? mOnBackAnimationCallback
-                                            : mOnBackInvokedCallback);
-                    mIsBackCallbackRegistered = false;
-                    if (DEBUG) Log.d(TAG, "is NOT VISIBLE to user, AND callback unregistered");
-                }
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG,
-                            "is NOT VISIBLE to user, BUT NO callback (or callback ALREADY "
-                                    + "unregistered)");
-                }
-            }
-        }
-    }
-
-    void onVisibleToUser() {
-        /* The LEDs are turned off when the notification panel is shown, even just a little bit.
-         * See also CentralSurfaces.setPanelExpanded for another place where we attempt to do
-         * this.
-         */
-        boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
-        boolean clearNotificationEffects =
-                !mPresenter.isPresenterFullyCollapsed() && (mState == StatusBarState.SHADE
-                        || mState == StatusBarState.SHADE_LOCKED);
-        int notificationLoad = mNotificationsController.getActiveNotificationsCount();
-        if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
-            notificationLoad = 1;
-        }
-        final int finalNotificationLoad = notificationLoad;
-        mUiBgExecutor.execute(() -> {
-            try {
-                mBarService.onPanelRevealed(clearNotificationEffects,
-                        finalNotificationLoad);
-            } catch (RemoteException ex) {
-                // Won't fail unless the world has ended.
-            }
-        });
-    }
-
-    void onInvisibleToUser() {
-        mUiBgExecutor.execute(() -> {
-            try {
-                mBarService.onPanelHidden();
-            } catch (RemoteException ex) {
-                // Won't fail unless the world has ended.
-            }
-        });
-    }
-
     private void logStateToEventlog() {
         boolean isShowing = mKeyguardStateController.isShowing();
         boolean isOccluded = mKeyguardStateController.isOccluded();
@@ -2325,11 +2154,12 @@
         // there's no surface we can show to the user. Note that the device goes fully interactive
         // late in the transition, so we also allow the device to start dozing once the screen has
         // turned off fully.
+        boolean keyguardShowingUnOccluded =
+                mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded();
         boolean keyguardForDozing = mDozeServiceHost.getDozingRequested()
                 && (!mDeviceInteractive || (isGoingToSleep()
-                    && (isScreenFullyOff()
-                        || (mKeyguardStateController.isShowing() && !isOccluded()))));
-        boolean isWakingAndOccluded = isOccluded() && isWakingOrAwake();
+                && (isScreenFullyOff() || keyguardShowingUnOccluded)));
+        boolean isWakingAndOccluded = mKeyguardStateController.isOccluded() && isWakingOrAwake();
         boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
                 || keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded;
         if (keyguardForDozing) {
@@ -2390,7 +2220,7 @@
         releaseGestureWakeLock();
         runLaunchTransitionEndRunnable();
         mKeyguardStateController.setLaunchTransitionFadingAway(false);
-        mPresenter.updateMediaMetaData(true /* metaDataChanged */, true);
+        mPresenterLazy.get().updateMediaMetaData(true /* metaDataChanged */, true);
     }
 
     /**
@@ -2414,7 +2244,7 @@
                 beforeFading.run();
             }
             updateScrimController();
-            mPresenter.updateMediaMetaData(false, true);
+            mPresenterLazy.get().updateMediaMetaData(false, true);
             mShadeSurface.resetAlpha();
             mShadeSurface.fadeOut(
                     FADE_KEYGUARD_START_DELAY, FADE_KEYGUARD_DURATION,
@@ -2648,7 +2478,7 @@
                 mStatusBarKeyguardViewManager.reset(true);
             } else if (mState == StatusBarState.KEYGUARD
                     && !mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
-                    && isKeyguardSecure()) {
+                    && mStatusBarKeyguardViewManager.isSecure()) {
                 mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
             }
         }
@@ -2728,11 +2558,6 @@
         mNavigationBarController.showPinningEscapeToast(mDisplayId);
     }
 
-    protected ViewRootImpl getViewRootImpl()  {
-        View root = mNotificationShadeWindowController.getWindowRootView();
-        if (root != null) return root.getViewRootImpl();
-        return null;
-    }
     /**
      * Propagation of the bouncer state, indicating that it's fully visible.
      */
@@ -2779,7 +2604,6 @@
             releaseGestureWakeLock();
             mLaunchCameraWhenFinishedWaking = false;
             mDeviceInteractive = false;
-            updateVisibleToUser();
 
             updateNotificationPanelTouchState();
             getNotificationShadeWindowViewController().cancelCurrentTouch();
@@ -2852,7 +2676,7 @@
                     // cancelling a sleep), from the power button, on a device with a power button
                     // FPS, and 'press to unlock' is required.
                     mShouldDelayWakeUpAnimation =
-                            !isPulsing()
+                            !mDozeServiceHost.isPulsing()
                                     && mStatusBarStateController.getDozeAmount() == 1f
                                     && mWakefulnessLifecycle.getLastWakeReason()
                                     == PowerManager.WAKE_REASON_POWER_BUTTON
@@ -2878,7 +2702,6 @@
                         /* wakingUp= */ true,
                         mShouldDelayWakeUpAnimation);
 
-                updateVisibleToUser();
                 updateIsKeyguard();
                 mShouldDelayLockscreenTransitionFromAod = mDozeParameters.getAlwaysOn()
                         && mFeatureFlags.isEnabled(
@@ -2994,11 +2817,6 @@
         }
     };
 
-    @Override
-    public int getWakefulnessState() {
-        return mWakefulnessLifecycle.getWakefulness();
-    }
-
     /**
      * @return true if the screen is currently fully off, i.e. has finished turning off and has
      * since not started turning on.
@@ -3064,7 +2882,7 @@
         if (mDevicePolicyManager.getCameraDisabled(null,
                 mLockscreenUserManager.getCurrentUserId())) {
             return false;
-        } else if (isKeyguardShowing() && isKeyguardSecure()) {
+        } else if (isKeyguardShowing() && mStatusBarKeyguardViewManager.isSecure()) {
             // Check if the admin has disabled the camera specifically for the keyguard
             return (mDevicePolicyManager.getKeyguardDisabledFeatures(null,
                     mLockscreenUserManager.getCurrentUserId())
@@ -3130,7 +2948,7 @@
         mScrimController.setExpansionAffectsAlpha(!unlocking);
 
         if (mAlternateBouncerInteractor.isVisibleState()) {
-            if ((!isOccluded() || mShadeSurface.isPanelExpanded())
+            if ((!mKeyguardStateController.isOccluded() || mShadeSurface.isPanelExpanded())
                     && (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED
                     || mTransitionToFullShadeProgress > 0f)) {
                 mScrimController.transitionTo(ScrimState.AUTH_SCRIMMED_SHADE);
@@ -3166,7 +2984,9 @@
             // This will cancel the keyguardFadingAway animation if it is running. We need to do
             // this as otherwise it can remain pending and leave keyguard in a weird state.
             mUnlockScrimCallback.onCancelled();
-        } else if (mKeyguardStateController.isShowing() && !isOccluded() && !unlocking) {
+        } else if (mKeyguardStateController.isShowing()
+                && !mKeyguardStateController.isOccluded()
+                && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
         } else if (mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
                 && !unlocking) {
@@ -3205,9 +3025,6 @@
 
     protected boolean mVisible;
 
-    // mScreenOnFromKeyguard && mVisible.
-    private boolean mVisibleToUser;
-
     protected DevicePolicyManager mDevicePolicyManager;
     private final PowerManager mPowerManager;
     protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -3331,21 +3148,8 @@
             if (visible) {
                 DejankUtils.notifyRendererOfExpensiveFrame(
                         getNotificationShadeWindowView(), "onShadeVisibilityChanged");
-            } else {
-                mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
-                        true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
             }
         }
-        updateVisibleToUser();
-    }
-
-    protected void updateVisibleToUser() {
-        boolean oldVisibleToUser = mVisibleToUser;
-        mVisibleToUser = mVisible && mDeviceInteractive;
-
-        if (oldVisibleToUser != mVisibleToUser) {
-            handleVisibleToUserChanged(mVisibleToUser);
-        }
     }
 
     /**
@@ -3381,11 +3185,6 @@
         return mBouncerShowingOverDream;
     }
 
-    @Override
-    public boolean isKeyguardSecure() {
-        return mStatusBarKeyguardViewManager.isSecure();
-    }
-
     // End Extra BaseStatusBarMethods.
 
     boolean isTransientShown() {
@@ -3403,11 +3202,6 @@
         }
     }
 
-    @Override
-    public void extendDozePulse(){
-        mDozeScrimController.extendPulse();
-    }
-
     private final KeyguardUpdateMonitorCallback mUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
@@ -3526,7 +3320,7 @@
                     // If we're visible and switched to SHADE_LOCKED (the user dragged
                     // down on the lockscreen), clear notification LED, vibration,
                     // ringing.
-                    // Other transitions are covered in handleVisibleToUserChanged().
+                    // Other transitions are covered in WindowRootViewVisibilityInteractor.
                     if (mVisible && (newState == StatusBarState.SHADE_LOCKED
                             || mStatusBarStateController.goingToFullShade())) {
                         clearNotificationEffects();
@@ -3551,7 +3345,8 @@
                     updateDozingState();
                     checkBarModes();
                     updateScrimController();
-                    mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
+                    mPresenterLazy.get()
+                            .updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
                     Trace.endSection();
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index 801cdbf..4849f64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -185,7 +185,7 @@
         return mDozingRequested;
     }
 
-    boolean isPulsing() {
+    public boolean isPulsing() {
         return mPulsing;
     }
 
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 cc41bf8..23b0ee0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.R
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeLogger
@@ -48,8 +49,9 @@
 
 private const val TAG = "PhoneStatusBarViewController"
 
-/** Controller for [PhoneStatusBarView].  */
-class PhoneStatusBarViewController private constructor(
+/** Controller for [PhoneStatusBarView]. */
+class PhoneStatusBarViewController
+private constructor(
     view: PhoneStatusBarView,
     @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
     private val centralSurfaces: CentralSurfaces,
@@ -61,42 +63,42 @@
     private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
     private val userChipViewModel: StatusBarUserChipViewModel,
     private val viewUtil: ViewUtil,
-    private val featureFlags: FeatureFlags,
+    private val sceneContainerFlags: SceneContainerFlags,
     private val configurationController: ConfigurationController,
     private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
 ) : ViewController<PhoneStatusBarView>(view) {
 
     private lateinit var statusContainer: View
 
-    private val configurationListener = object : ConfigurationController.ConfigurationListener {
-        override fun onConfigChanged(newConfig: Configuration?) {
-            mView.updateResources()
+    private val configurationListener =
+        object : ConfigurationController.ConfigurationListener {
+            override fun onConfigChanged(newConfig: Configuration?) {
+                mView.updateResources()
+            }
         }
-    }
 
     override fun onViewAttached() {
         statusContainer = mView.requireViewById(R.id.system_icons)
         statusContainer.setOnHoverListener(
-            statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer))
+            statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
+        )
         if (moveFromCenterAnimationController == null) return
 
         val statusBarLeftSide: View =
-                mView.requireViewById(R.id.status_bar_start_side_except_heads_up)
+            mView.requireViewById(R.id.status_bar_start_side_except_heads_up)
         val systemIconArea: ViewGroup = mView.requireViewById(R.id.status_bar_end_side_content)
 
-        val viewsToAnimate = arrayOf(
-            statusBarLeftSide,
-            systemIconArea
-        )
+        val viewsToAnimate = arrayOf(statusBarLeftSide, systemIconArea)
 
-        mView.viewTreeObserver.addOnPreDrawListener(object :
-            ViewTreeObserver.OnPreDrawListener {
-            override fun onPreDraw(): Boolean {
-                moveFromCenterAnimationController.onViewsReady(viewsToAnimate)
-                mView.viewTreeObserver.removeOnPreDrawListener(this)
-                return true
+        mView.viewTreeObserver.addOnPreDrawListener(
+            object : ViewTreeObserver.OnPreDrawListener {
+                override fun onPreDraw(): Boolean {
+                    moveFromCenterAnimationController.onViewsReady(viewsToAnimate)
+                    mView.viewTreeObserver.removeOnPreDrawListener(this)
+                    return true
+                }
             }
-        })
+        )
 
         mView.addOnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
             val widthChanged = right - left != oldRight - oldLeft
@@ -121,8 +123,7 @@
         mView.init(userChipViewModel)
     }
 
-    override fun onInit() {
-    }
+    override fun onInit() {}
 
     fun setImportantForAccessibility(mode: Int) {
         mView.importantForAccessibility = mode
@@ -151,10 +152,11 @@
     fun onTouch(event: MotionEvent) {
         if (statusBarWindowStateController.windowIsShowing()) {
             val upOrCancel =
-                event.action == MotionEvent.ACTION_UP ||
-                    event.action == MotionEvent.ACTION_CANCEL
-            centralSurfaces.setInteracting(WINDOW_STATUS_BAR,
-                !upOrCancel || shadeController.isExpandedVisible)
+                event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL
+            centralSurfaces.setInteracting(
+                WINDOW_STATUS_BAR,
+                !upOrCancel || shadeController.isExpandedVisible
+            )
         }
     }
 
@@ -171,15 +173,20 @@
             // panel view.
             if (!centralSurfaces.commandQueuePanelsEnabled) {
                 if (event.action == MotionEvent.ACTION_DOWN) {
-                    Log.v(TAG, String.format("onTouchForwardedFromStatusBar: panel disabled, " +
-                        "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"))
+                    Log.v(
+                        TAG,
+                        String.format(
+                            "onTouchForwardedFromStatusBar: panel disabled, " +
+                                "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"
+                        )
+                    )
                 }
                 return false
             }
 
             // If scene framework is enabled, route the touch to it and
             // ignore the rest of the gesture.
-            if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+            if (sceneContainerFlags.isEnabled()) {
                 windowRootView.get().dispatchTouchEvent(event)
                 return true
             }
@@ -188,12 +195,13 @@
                 // If the view that would receive the touch is disabled, just have status
                 // bar eat the gesture.
                 if (!shadeViewController.isViewEnabled) {
-                    shadeLogger.logMotionEvent(event,
-                        "onTouchForwardedFromStatusBar: panel view disabled")
+                    shadeLogger.logMotionEvent(
+                        event,
+                        "onTouchForwardedFromStatusBar: panel view disabled"
+                    )
                     return true
                 }
-                if (shadeViewController.isFullyCollapsed &&
-                    event.y < 1f) {
+                if (shadeViewController.isFullyCollapsed && event.y < 1f) {
                     // b/235889526 Eat events on the top edge of the phone when collapsed
                     shadeLogger.logMotionEvent(event, "top edge touch ignored")
                     return true
@@ -218,9 +226,7 @@
                 else -> super.getViewCenter(view, outPoint)
             }
 
-        /**
-         * Returns start or end (based on [isStart]) center point of the view
-         */
+        /** Returns start or end (based on [isStart]) center point of the view */
         private fun getViewEdgeCenter(view: View, outPoint: Point, isStart: Boolean) {
             val isRtl = view.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
             val isLeftEdge = isRtl xor isStart
@@ -236,11 +242,14 @@
         }
     }
 
-    class Factory @Inject constructor(
+    class Factory
+    @Inject
+    constructor(
         private val unfoldComponent: Optional<SysUIUnfoldComponent>,
         @Named(UNFOLD_STATUS_BAR)
         private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
         private val featureFlags: FeatureFlags,
+        private val sceneContainerFlags: SceneContainerFlags,
         private val userChipViewModel: StatusBarUserChipViewModel,
         private val centralSurfaces: CentralSurfaces,
         private val statusBarWindowStateController: StatusBarWindowStateController,
@@ -252,9 +261,7 @@
         private val configurationController: ConfigurationController,
         private val statusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory,
     ) {
-        fun create(
-            view: PhoneStatusBarView
-        ): PhoneStatusBarViewController {
+        fun create(view: PhoneStatusBarView): PhoneStatusBarViewController {
             val statusBarMoveFromCenterAnimationController =
                 if (featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)) {
                     unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController()
@@ -274,10 +281,10 @@
                 statusBarMoveFromCenterAnimationController,
                 userChipViewModel,
                 viewUtil,
-                featureFlags,
+                sceneContainerFlags,
                 configurationController,
                 statusOverlayHoverListenerFactory,
             )
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 62a8cfd..40432ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -763,7 +763,7 @@
      * Sets the amount of vertical over scroll that should be performed on the notifications scrim.
      */
     public void setNotificationsOverScrollAmount(int overScrollAmount) {
-        mNotificationsScrim.setTranslationY(overScrollAmount);
+        if (mNotificationsScrim != null) mNotificationsScrim.setTranslationY(overScrollAmount);
     }
 
     /**
@@ -1480,7 +1480,7 @@
 
     public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
         // TODO: remove this. This is necessary because of an order-of-operations limitation.
-        // The fix is to move more of these class into @CentralSurfacesScope
+        // The fix is to move more of these class into @SysUISingleton.
         if (mScrimBehind == null) {
             mScrimBehindChangeRunnable = changeRunnable;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index d5cb6b6..4878d45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -81,11 +81,7 @@
     /** Removes an icon that had come from an active tile service. */
     void removeIconForTile(String slot);
 
-    /**
-     * Adds or updates an icon for the given slot for **internal system icons**.
-     *
-     * TODO(b/265307726): Re-name this to `setInternalIcon`.
-     */
+    /** Adds or updates an icon for the given slot for **internal system icons**. */
     void setIcon(String slot, int resourceId, CharSequence contentDescription);
 
     /**
@@ -127,11 +123,6 @@
      */
     void removeIcon(String slot, int tag);
 
-    /**
-     * TODO(b/265307726): Re-name this to `removeAllIconsForInternalSlot`.
-     */
-    void removeAllIconsForSlot(String slot);
-
     // TODO: See if we can rename this tunable name.
     String ICON_HIDE_LIST = "icon_blacklist";
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 553cbc5..0f4d68c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -385,13 +385,7 @@
     }
 
     private void removeAllIconsForExternalSlot(String slotName) {
-        removeAllIconsForSlot(createExternalSlotName(slotName));
-    }
-
-    /** */
-    @Override
-    public void removeAllIconsForSlot(String slotName) {
-        removeAllIconsForSlot(slotName, /* fromNewPipeline */ false);
+        removeAllIconsForSlot(createExternalSlotName(slotName), /* fromNewPipeline= */ false);
     }
 
     private void removeAllIconsForSlot(String slotName, boolean fromNewPipeline) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index fa9b9d2..5773612 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -34,9 +34,8 @@
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -85,7 +84,7 @@
             ShadeExpansionStateManager shadeExpansionStateManager,
             Provider<SceneInteractor> sceneInteractor,
             Provider<JavaAdapter> javaAdapter,
-            FeatureFlags featureFlags,
+            SceneContainerFlags sceneContainerFlags,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController
     ) {
         mContext = context;
@@ -123,7 +122,7 @@
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
         shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged);
 
-        if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+        if (sceneContainerFlags.isEnabled()) {
             javaAdapter.get().alwaysCollectFlow(
                     sceneInteractor.get().isVisible(),
                     this::onShadeExpansionFullyChanged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 37f032b..2c15e27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -125,6 +125,7 @@
 
     // FrameCallback used to delay starting the light reveal animation until the next frame
     private val startLightRevealCallback = TraceUtils.namedRunnable("startLightReveal") {
+        lightRevealAnimationPlaying = true
         lightRevealAnimator.start()
     }
 
@@ -268,7 +269,6 @@
             decidedToAnimateGoingToSleep = true
 
             shouldAnimateInKeyguard = true
-            lightRevealAnimationPlaying = true
 
             // Start the animation on the next frame. startAnimation() is called after
             // PhoneWindowManager makes a binder call to System UI on
@@ -283,7 +283,8 @@
                 // dispatched, a race condition could make it possible for this callback to be run
                 // as the device is waking up. That results in the AOD UI being shown while we wake
                 // up, with unpredictable consequences.
-                if (!powerManager.isInteractive(Display.DEFAULT_DISPLAY)) {
+                if (!powerManager.isInteractive(Display.DEFAULT_DISPLAY) &&
+                        shouldAnimateInKeyguard) {
                     aodUiAnimationPlaying = true
 
                     // Show AOD. That'll cause the KeyguardVisibilityHelper to call
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
deleted file mode 100644
index 1a04b91..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ /dev/null
@@ -1,76 +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.phone.dagger;
-
-import static com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.STATUS_BAR_FRAGMENT;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.android.systemui.shade.ShadeHeaderController;
-import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
-
-import dagger.Subcomponent;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-/**
- * Dagger subcomponent for classes (semi-)related to the status bar. The component is created once
- * inside {@link CentralSurfacesImpl} and never re-created.
- *
- * TODO(b/197137564): This should likely be re-factored a bit. It includes classes that aren't
- * directly related to status bar functionality, like multiple notification classes. And, the fact
- * that it has many getter methods indicates that we need to access many of these classes from
- * outside the component. Should more items be moved *into* this component to avoid so many getters?
- */
-@Subcomponent(modules = {
-        StatusBarViewModule.class,
-})
-@CentralSurfacesComponent.CentralSurfacesScope
-public interface CentralSurfacesComponent {
-    /**
-     * Builder for {@link CentralSurfacesComponent}.
-     */
-    @Subcomponent.Factory
-    interface Factory {
-        CentralSurfacesComponent create();
-    }
-
-    /**
-     * Scope annotation for singleton items within the CentralSurfacesComponent.
-     */
-    @Documented
-    @Retention(RUNTIME)
-    @Scope
-    @interface CentralSurfacesScope {}
-
-    /**
-     * Creates a {@link ShadeHeaderController}.
-     */
-    ShadeHeaderController getLargeScreenShadeHeaderController();
-
-    /**
-     * Creates a new {@link CollapsedStatusBarFragment} each time it's called. See
-     * {@link StatusBarViewModule#createCollapsedStatusBarFragment}.
-     */
-    @Named(STATUS_BAR_FRAGMENT)
-    CollapsedStatusBarFragment createCollapsedStatusBarFragment();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
deleted file mode 100644
index ebdde78..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ /dev/null
@@ -1,127 +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.phone.dagger;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.OperatorNameViewController;
-import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
-import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
-import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
-import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder;
-import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.window.StatusBarWindowStateController;
-import com.android.systemui.util.CarrierConfigTracker;
-import com.android.systemui.util.settings.SecureSettings;
-
-import dagger.Module;
-import dagger.Provides;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Named;
-
-/**
- * A module for {@link CentralSurfacesComponent.CentralSurfacesScope} components.
- *
- * @deprecated CentralSurfacesScope will be removed shortly (b/277762009). Classes should be
- *   annotated with @SysUISingleton instead.
- */
-@Module(subcomponents = StatusBarFragmentComponent.class)
-@Deprecated
-public abstract class StatusBarViewModule {
-
-    public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
-
-    /**
-     * Creates a new {@link CollapsedStatusBarFragment}.
-     *
-     * **IMPORTANT**: This method intentionally does not have
-     * {@link CentralSurfacesComponent.CentralSurfacesScope}, which means a new fragment *will* be
-     * created each time this method is called. This is intentional because we need fragments to
-     * re-created in certain lifecycle scenarios.
-     *
-     * This provider is {@link Named} such that it does not conflict with the provider inside of
-     * {@link StatusBarFragmentComponent}.
-     */
-    @Provides
-    @Named(STATUS_BAR_FRAGMENT)
-    public static CollapsedStatusBarFragment createCollapsedStatusBarFragment(
-            StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
-            OngoingCallController ongoingCallController,
-            SystemStatusAnimationScheduler animationScheduler,
-            StatusBarLocationPublisher locationPublisher,
-            NotificationIconAreaController notificationIconAreaController,
-            ShadeExpansionStateManager shadeExpansionStateManager,
-            FeatureFlags featureFlags,
-            StatusBarIconController statusBarIconController,
-            StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
-            CollapsedStatusBarViewModel collapsedStatusBarViewModel,
-            CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
-            StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
-            KeyguardStateController keyguardStateController,
-            ShadeViewController shadeViewController,
-            StatusBarStateController statusBarStateController,
-            CommandQueue commandQueue,
-            CarrierConfigTracker carrierConfigTracker,
-            CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
-            OperatorNameViewController.Factory operatorNameViewControllerFactory,
-            SecureSettings secureSettings,
-            @Main Executor mainExecutor,
-            DumpManager dumpManager,
-            StatusBarWindowStateController statusBarWindowStateController,
-            KeyguardUpdateMonitor keyguardUpdateMonitor
-    ) {
-        return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory,
-                ongoingCallController,
-                animationScheduler,
-                locationPublisher,
-                notificationIconAreaController,
-                shadeExpansionStateManager,
-                featureFlags,
-                statusBarIconController,
-                darkIconManagerFactory,
-                collapsedStatusBarViewModel,
-                collapsedStatusBarViewBinder,
-                statusBarHideIconsForBouncerManager,
-                keyguardStateController,
-                shadeViewController,
-                statusBarStateController,
-                commandQueue,
-                carrierConfigTracker,
-                collapsedStatusBarFragmentLogger,
-                operatorNameViewControllerFactory,
-                secureSettings,
-                mainExecutor,
-                dumpManager,
-                statusBarWindowStateController,
-                keyguardUpdateMonitor);
-    }
-}
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 2efdf8a..66f0f59 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
@@ -29,7 +29,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.widget.LinearLayout;
 
 import androidx.annotation.VisibleForTesting;
@@ -85,6 +84,8 @@
 import java.util.Set;
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+
 /**
  * Contains the collapsed status bar and handles hiding/showing based on disable flags
  * and keyguard state. Also manages lifecycle to make sure the views it contains are being
@@ -203,7 +204,7 @@
         mTransitionFromLockscreenToDreamStarted = false;
     };
 
-    @SuppressLint("ValidFragment")
+    @Inject
     public CollapsedStatusBarFragment(
             StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
             OngoingCallController ongoingCallController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentStartable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentStartable.kt
new file mode 100644
index 0000000..55af0e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentStartable.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.fragment
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.fragments.FragmentService
+import com.android.systemui.qs.QSFragmentStartable
+import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+import javax.inject.Provider
+
+/**
+ * Provides [FragmentService] with a way to automatically inflate [CollapsedStatusBarFragment],
+ * similar to [QSFragmentStartable].
+ */
+@SysUISingleton
+class CollapsedStatusBarFragmentStartable
+@Inject
+constructor(
+    private val fragmentService: FragmentService,
+    private val collapsedstatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>
+) : CoreStartable {
+    override fun start() {
+        fragmentService.addFragmentInstantiationProvider(
+            CollapsedStatusBarFragment::class.java,
+            collapsedstatusBarFragmentProvider,
+        )
+    }
+}
+
+@Module(subcomponents = [StatusBarFragmentComponent::class])
+interface CollapsedStatusBarFragmentStartableModule {
+    @Binds
+    @IntoMap
+    @ClassKey(CollapsedStatusBarFragmentStartable::class)
+    fun bindsCollapsedStatusBarFragmentStartable(
+        startable: CollapsedStatusBarFragmentStartable
+    ): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractor.kt
new file mode 100644
index 0000000..3709e4c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractor.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.ethernet.domain
+
+import com.android.settingslib.AccessibilityContentDescriptions
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Currently we don't do much to interact with ethernet. We simply need a place to map between the
+ * connectivity state of a default ethernet connection, and an icon representing that connection.
+ */
+@SysUISingleton
+class EthernetInteractor
+@Inject
+constructor(
+    connectivityRepository: ConnectivityRepository,
+) {
+    /** Icon representing the current connectivity status of the ethernet connection */
+    val icon: Flow<Icon.Resource?> =
+        connectivityRepository.defaultConnections.map {
+            if (it.ethernet.isDefault) {
+                if (it.isValidated) {
+                    Icon.Resource(
+                        R.drawable.stat_sys_ethernet_fully,
+                        ContentDescription.Resource(
+                            AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES[1]
+                        )
+                    )
+                } else {
+                    Icon.Resource(
+                        R.drawable.stat_sys_ethernet,
+                        ContentDescription.Resource(
+                            AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES[0]
+                        )
+                    )
+                }
+            } else {
+                null
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index 051e88f..02473f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -16,9 +16,11 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data
 
+import android.content.Intent
 import android.telephony.ServiceState
 import android.telephony.SignalStrength
 import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
 import com.android.settingslib.SignalIcon
 import com.android.settingslib.mobile.MobileMappings
 import com.android.systemui.dagger.SysUISingleton
@@ -162,6 +164,28 @@
     fun logOnSubscriptionsChanged() {
         buffer.log(TAG, LogLevel.INFO, {}, { "onSubscriptionsChanged" })
     }
+
+    fun logServiceProvidersUpdatedBroadcast(intent: Intent) {
+        val showSpn = intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_SPN, false)
+        val spn = intent.getStringExtra(TelephonyManager.EXTRA_DATA_SPN)
+        val showPlmn = intent.getBooleanExtra(TelephonyManager.EXTRA_SHOW_PLMN, false)
+        val plmn = intent.getStringExtra(TelephonyManager.EXTRA_PLMN)
+
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                bool1 = showSpn
+                str1 = spn
+                bool2 = showPlmn
+                str2 = plmn
+            },
+            {
+                "Intent: ACTION_SERVICE_PROVIDERS_UPDATED." +
+                    " showSpn=$bool1 spn=$str1 showPlmn=$bool2 plmn=$str2"
+            }
+        )
+    }
 }
 
 private const val TAG = "MobileInputLog"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index 1f1ac92..cd68621 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
 
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
 import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
 import android.telephony.CellSignalStrengthCdma
 import android.telephony.ServiceState
 import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
 import android.telephony.TelephonyCallback
 import android.telephony.TelephonyDisplayInfo
@@ -34,6 +38,7 @@
 import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
 import com.android.settingslib.Utils
 import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.log.table.TableLogBuffer
@@ -81,6 +86,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 class MobileConnectionRepositoryImpl(
     override val subId: Int,
+    private val context: Context,
     subscriptionModel: StateFlow<SubscriptionModel?>,
     defaultNetworkName: NetworkNameModel,
     networkNameSeparator: String,
@@ -323,16 +329,35 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), telephonyManager.simCarrierId)
 
+    /** BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here */
+    @SuppressLint("RegisterReceiverViaContext")
     override val networkName: StateFlow<NetworkNameModel> =
-        broadcastDispatcher
-            .broadcastFlow(
-                filter = IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED),
-                map = { intent, _ -> intent },
-            )
-            .filter { intent ->
-                intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, INVALID_SUBSCRIPTION_ID) == subId
+        conflatedCallbackFlow {
+                val receiver =
+                    object : BroadcastReceiver() {
+                        override fun onReceive(context: Context, intent: Intent) {
+                            if (
+                                intent.getIntExtra(
+                                    EXTRA_SUBSCRIPTION_INDEX,
+                                    INVALID_SUBSCRIPTION_ID
+                                ) == subId
+                            ) {
+                                logger.logServiceProvidersUpdatedBroadcast(intent)
+                                trySend(
+                                    intent.toNetworkNameModel(networkNameSeparator)
+                                        ?: defaultNetworkName
+                                )
+                            }
+                        }
+                    }
+
+                context.registerReceiver(
+                    receiver,
+                    IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED)
+                )
+
+                awaitClose { context.unregisterReceiver(receiver) }
             }
-            .map { intent -> intent.toNetworkNameModel(networkNameSeparator) ?: defaultNetworkName }
             .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
 
     override val dataEnabled = run {
@@ -349,6 +374,7 @@
     class Factory
     @Inject
     constructor(
+        private val context: Context,
         private val broadcastDispatcher: BroadcastDispatcher,
         private val telephonyManager: TelephonyManager,
         private val logger: MobileInputLogger,
@@ -366,6 +392,7 @@
         ): MobileConnectionRepository {
             return MobileConnectionRepositoryImpl(
                 subId,
+                context,
                 subscriptionModel,
                 defaultNetworkName,
                 networkNameSeparator,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 4cfde5b..4bf297c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
 
 import android.content.Context
-import android.telephony.CarrierConfigManager
 import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.graph.SignalDrawable
 import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
 import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
 import com.android.systemui.dagger.qualifiers.Application
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.DefaultIcon
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.OverriddenIcon
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,24 +61,17 @@
      */
     val isDataConnected: StateFlow<Boolean>
 
-    /** Only true if mobile is the default transport but is not validated, otherwise false */
-    val isDefaultConnectionFailed: StateFlow<Boolean>
-
     /** True if we consider this connection to be in service, i.e. can make calls */
     val isInService: StateFlow<Boolean>
 
-    // TODO(b/256839546): clarify naming of default vs active
-    /** True if we want to consider the data connection enabled */
-    val isDefaultDataEnabled: StateFlow<Boolean>
-
     /** Observable for the data enabled state of this connection */
     val isDataEnabled: StateFlow<Boolean>
 
     /** True if the RAT icon should always be displayed and false otherwise. */
     val alwaysShowDataRatIcon: StateFlow<Boolean>
 
-    /** True if the CDMA level should be preferred over the primary level. */
-    val alwaysUseCdmaLevel: StateFlow<Boolean>
+    /** Canonical representation of the current mobile signal strength as a triangle. */
+    val signalLevelIcon: StateFlow<SignalIconModel>
 
     /** Observable for RAT type (network type) indicator */
     val networkTypeIconGroup: StateFlow<NetworkTypeIconModel>
@@ -108,9 +102,6 @@
     /** True if there is only one active subscription. */
     val isSingleCarrier: StateFlow<Boolean>
 
-    /** True if this line of service is emergency-only */
-    val isEmergencyOnly: StateFlow<Boolean>
-
     /**
      * True if this connection is considered roaming. The roaming bit can come from [ServiceState],
      * or directly from the telephony manager's CDMA ERI number value. Note that we don't consider a
@@ -118,12 +109,6 @@
      */
     val isRoaming: StateFlow<Boolean>
 
-    /** Int describing the connection strength. 0-4 OR 1-5. See [numberOfLevels] */
-    val level: StateFlow<Int>
-
-    /** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
-    val numberOfLevels: StateFlow<Int>
-
     /** See [MobileIconsInteractor.isForceHidden]. */
     val isForceHidden: Flow<Boolean>
 
@@ -141,12 +126,12 @@
     @Application scope: CoroutineScope,
     defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
     override val alwaysShowDataRatIcon: StateFlow<Boolean>,
-    override val alwaysUseCdmaLevel: StateFlow<Boolean>,
+    alwaysUseCdmaLevel: StateFlow<Boolean>,
     override val isSingleCarrier: StateFlow<Boolean>,
     override val mobileIsDefault: StateFlow<Boolean>,
     defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
     defaultMobileIconGroup: StateFlow<MobileIconGroup>,
-    override val isDefaultConnectionFailed: StateFlow<Boolean>,
+    isDefaultConnectionFailed: StateFlow<Boolean>,
     override val isForceHidden: Flow<Boolean>,
     connectionRepository: MobileConnectionRepository,
     private val context: Context,
@@ -170,8 +155,6 @@
             .distinctUntilChanged()
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
-    override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
-
     override val networkName =
         combine(connectionRepository.operatorAlphaShort, connectionRepository.networkName) {
                 operatorAlphaShort,
@@ -255,8 +238,6 @@
                 DefaultIcon(defaultMobileIconGroup.value),
             )
 
-    override val isEmergencyOnly = connectionRepository.isEmergencyOnly
-
     override val isRoaming: StateFlow<Boolean> =
         combine(
                 connectionRepository.carrierNetworkChangeActive,
@@ -274,7 +255,7 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
-    override val level: StateFlow<Int> =
+    private val level: StateFlow<Int> =
         combine(
                 connectionRepository.isGsm,
                 connectionRepository.primaryLevel,
@@ -290,7 +271,7 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
 
-    override val numberOfLevels: StateFlow<Int> =
+    private val numberOfLevels: StateFlow<Int> =
         connectionRepository.numberOfLevels.stateIn(
             scope,
             SharingStarted.WhileSubscribed(),
@@ -305,4 +286,54 @@
     override val isInService = connectionRepository.isInService
 
     override val isAllowedDuringAirplaneMode = connectionRepository.isAllowedDuringAirplaneMode
+
+    /** Whether or not to show the error state of [SignalDrawable] */
+    private val showExclamationMark: StateFlow<Boolean> =
+        combine(
+                defaultSubscriptionHasDataEnabled,
+                isDefaultConnectionFailed,
+                isInService,
+            ) { isDefaultDataEnabled, isDefaultConnectionFailed, isInService ->
+                !isDefaultDataEnabled || isDefaultConnectionFailed || !isInService
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), true)
+
+    private val shownLevel: StateFlow<Int> =
+        combine(
+                level,
+                isInService,
+            ) { level, isInService ->
+                if (isInService) level else 0
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+
+    override val signalLevelIcon: StateFlow<SignalIconModel> = run {
+        val initial =
+            SignalIconModel(
+                level = shownLevel.value,
+                numberOfLevels = numberOfLevels.value,
+                showExclamationMark = showExclamationMark.value,
+                carrierNetworkChange = carrierNetworkChangeActive.value,
+            )
+        combine(
+                shownLevel,
+                numberOfLevels,
+                showExclamationMark,
+                carrierNetworkChangeActive,
+            ) { shownLevel, numberOfLevels, showExclamationMark, carrierNetworkChange ->
+                SignalIconModel(
+                    shownLevel,
+                    numberOfLevels,
+                    showExclamationMark,
+                    carrierNetworkChange,
+                )
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "icon",
+                initialValue = initial,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index d08808b..62150e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
 import com.android.systemui.util.CarrierConfigTracker
+import java.lang.ref.WeakReference
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -70,6 +71,12 @@
     /** True if the active mobile data subscription has data enabled */
     val activeDataConnectionHasDataEnabled: StateFlow<Boolean>
 
+    /**
+     * Flow providing a reference to the Interactor for the active data subId. This represents the
+     * [MobileConnectionInteractor] responsible for the active data connection, if any.
+     */
+    val activeDataIconInteractor: StateFlow<MobileIconInteractor?>
+
     /** True if the RAT icon should always be displayed and false otherwise. */
     val alwaysShowDataRatIcon: StateFlow<Boolean>
 
@@ -96,9 +103,9 @@
 
     /**
      * Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
-     * subId. Will throw if the ID is invalid
+     * subId.
      */
-    fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
+    fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
 }
 
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@@ -116,6 +123,9 @@
     private val context: Context,
 ) : MobileIconsInteractor {
 
+    // Weak reference lookup for created interactors
+    private val reuseCache = mutableMapOf<Int, WeakReference<MobileIconInteractor>>()
+
     override val mobileIsDefault =
         combine(
                 mobileConnectionsRepo.mobileIsDefault,
@@ -138,6 +148,17 @@
             .flatMapLatest { it?.dataEnabled ?: flowOf(false) }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
+    override val activeDataIconInteractor: StateFlow<MobileIconInteractor?> =
+        mobileConnectionsRepo.activeMobileDataSubscriptionId
+            .mapLatest {
+                if (it != null) {
+                    getMobileConnectionInteractorForSubId(it)
+                } else {
+                    null
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
     private val unfilteredSubscriptions: Flow<List<SubscriptionModel>> =
         mobileConnectionsRepo.subscriptions
 
@@ -306,21 +327,25 @@
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
     /** Vends out new [MobileIconInteractor] for a particular subId */
-    override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+    override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+        reuseCache[subId]?.get() ?: createMobileConnectionInteractorForSubId(subId)
+
+    private fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
         MobileIconInteractorImpl(
-            scope,
-            activeDataConnectionHasDataEnabled,
-            alwaysShowDataRatIcon,
-            alwaysUseCdmaLevel,
-            isSingleCarrier,
-            mobileIsDefault,
-            defaultMobileIconMapping,
-            defaultMobileIconGroup,
-            isDefaultConnectionFailed,
-            isForceHidden,
-            mobileConnectionsRepo.getRepoForSubId(subId),
-            context,
-        )
+                scope,
+                activeDataConnectionHasDataEnabled,
+                alwaysShowDataRatIcon,
+                alwaysUseCdmaLevel,
+                isSingleCarrier,
+                mobileIsDefault,
+                defaultMobileIconMapping,
+                defaultMobileIconGroup,
+                isDefaultConnectionFailed,
+                isForceHidden,
+                mobileConnectionsRepo.getRepoForSubId(subId),
+                context,
+            )
+            .also { reuseCache[subId] = WeakReference(it) }
 
     companion object {
         private const val LOGGING_PREFIX = "Intr"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/model/SignalIconModel.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/model/SignalIconModel.kt
index 6de3f85..e58f081 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/model/SignalIconModel.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.mobile.ui.model
+package com.android.systemui.statusbar.pipeline.mobile.domain.model
 
 import com.android.settingslib.graph.SignalDrawable
 import com.android.systemui.log.table.Diffable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
index cffc833..a1a5370 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/VerboseMobileViewLogger.kt
@@ -22,8 +22,8 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.statusbar.pipeline.dagger.VerboseMobileViewLog
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger.Companion.getIdForLogging
-import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
 import javax.inject.Inject
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 4b2fb43..249ca35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -26,6 +26,7 @@
 import android.widget.Space
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.settingslib.graph.SignalDrawable
 import com.android.systemui.R
@@ -64,7 +65,7 @@
         val roamingSpace = view.requireViewById<Space>(R.id.mobile_roaming_space)
         val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
 
-        view.isVisible = true
+        view.isVisible = viewModel.isVisible.value
         iconView.isVisible = true
 
         // TODO(b/238425913): We should log this visibility state.
@@ -77,108 +78,122 @@
         var isCollecting = false
 
         view.repeatWhenAttached {
-            repeatOnLifecycle(Lifecycle.State.STARTED) {
-                logger.logCollectionStarted(view, viewModel)
-                isCollecting = true
-
-                launch {
-                    visibilityState.collect { state ->
-                        when (state) {
-                            STATE_ICON -> {
-                                mobileGroupView.visibility = VISIBLE
-                                dotView.visibility = GONE
-                            }
-                            STATE_DOT -> {
-                                mobileGroupView.visibility = INVISIBLE
-                                dotView.visibility = VISIBLE
-                            }
-                            STATE_HIDDEN -> {
-                                mobileGroupView.visibility = INVISIBLE
-                                dotView.visibility = INVISIBLE
-                            }
+            lifecycleScope.launch {
+                repeatOnLifecycle(Lifecycle.State.CREATED) {
+                    // isVisible controls the visibility state of the outer group, and thus it needs
+                    // to run in the CREATED lifecycle so it can continue to watch while invisible
+                    // See (b/291031862) for details
+                    launch {
+                        viewModel.isVisible.collect { isVisible ->
+                            viewModel.verboseLogger?.logBinderReceivedVisibility(
+                                view,
+                                viewModel.subscriptionId,
+                                isVisible
+                            )
+                            view.isVisible = isVisible
+                            // [StatusIconContainer] can get out of sync sometimes. Make sure to
+                            // request another layout when this changes.
+                            view.requestLayout()
                         }
                     }
                 }
+            }
 
-                launch {
-                    viewModel.isVisible.collect { isVisible ->
-                        viewModel.verboseLogger?.logBinderReceivedVisibility(
-                            view,
-                            viewModel.subscriptionId,
-                            isVisible
-                        )
-                        view.isVisible = isVisible
+            lifecycleScope.launch {
+                repeatOnLifecycle(Lifecycle.State.STARTED) {
+                    logger.logCollectionStarted(view, viewModel)
+                    isCollecting = true
+
+                    launch {
+                        visibilityState.collect { state ->
+                            when (state) {
+                                STATE_ICON -> {
+                                    mobileGroupView.visibility = VISIBLE
+                                    dotView.visibility = GONE
+                                }
+                                STATE_DOT -> {
+                                    mobileGroupView.visibility = INVISIBLE
+                                    dotView.visibility = VISIBLE
+                                }
+                                STATE_HIDDEN -> {
+                                    mobileGroupView.visibility = INVISIBLE
+                                    dotView.visibility = INVISIBLE
+                                }
+                            }
+                        }
                     }
-                }
 
-                // Set the icon for the triangle
-                launch {
-                    viewModel.icon.distinctUntilChanged().collect { icon ->
-                        viewModel.verboseLogger?.logBinderReceivedSignalIcon(
-                            view,
-                            viewModel.subscriptionId,
-                            icon,
-                        )
-                        mobileDrawable.level = icon.toSignalDrawableState()
+                    // Set the icon for the triangle
+                    launch {
+                        viewModel.icon.distinctUntilChanged().collect { icon ->
+                            viewModel.verboseLogger?.logBinderReceivedSignalIcon(
+                                view,
+                                viewModel.subscriptionId,
+                                icon,
+                            )
+                            mobileDrawable.level = icon.toSignalDrawableState()
+                        }
                     }
-                }
 
-                launch {
-                    viewModel.contentDescription.distinctUntilChanged().collect {
-                        ContentDescriptionViewBinder.bind(it, view)
+                    launch {
+                        viewModel.contentDescription.distinctUntilChanged().collect {
+                            ContentDescriptionViewBinder.bind(it, view)
+                        }
                     }
-                }
 
-                // Set the network type icon
-                launch {
-                    viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
-                        viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
-                            view,
-                            viewModel.subscriptionId,
-                            dataTypeId,
-                        )
-                        dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
-                        networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
+                    // Set the network type icon
+                    launch {
+                        viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
+                            viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
+                                view,
+                                viewModel.subscriptionId,
+                                dataTypeId,
+                            )
+                            dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
+                            networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
+                        }
                     }
-                }
 
-                // Set the roaming indicator
-                launch {
-                    viewModel.roaming.distinctUntilChanged().collect { isRoaming ->
-                        roamingView.isVisible = isRoaming
-                        roamingSpace.isVisible = isRoaming
+                    // Set the roaming indicator
+                    launch {
+                        viewModel.roaming.distinctUntilChanged().collect { isRoaming ->
+                            roamingView.isVisible = isRoaming
+                            roamingSpace.isVisible = isRoaming
+                        }
                     }
-                }
 
-                // Set the activity indicators
-                launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
+                    // Set the activity indicators
+                    launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
 
-                launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
+                    launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
 
-                launch {
-                    viewModel.activityContainerVisible.collect { activityContainer.isVisible = it }
-                }
-
-                // Set the tint
-                launch {
-                    iconTint.collect { tint ->
-                        val tintList = ColorStateList.valueOf(tint)
-                        iconView.imageTintList = tintList
-                        networkTypeView.imageTintList = tintList
-                        roamingView.imageTintList = tintList
-                        activityIn.imageTintList = tintList
-                        activityOut.imageTintList = tintList
-                        dotView.setDecorColor(tint)
+                    launch {
+                        viewModel.activityContainerVisible.collect {
+                            activityContainer.isVisible = it
+                        }
                     }
-                }
 
-                launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
+                    // Set the tint
+                    launch {
+                        iconTint.collect { tint ->
+                            val tintList = ColorStateList.valueOf(tint)
+                            iconView.imageTintList = tintList
+                            networkTypeView.imageTintList = tintList
+                            roamingView.imageTintList = tintList
+                            activityIn.imageTintList = tintList
+                            activityOut.imageTintList = tintList
+                            dotView.setDecorColor(tint)
+                        }
+                    }
 
-                try {
-                    awaitCancellation()
-                } finally {
-                    isCollecting = false
-                    logger.logCollectionStopped(view, viewModel)
+                    launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
+
+                    try {
+                        awaitCancellation()
+                    } finally {
+                        isCollecting = false
+                        logger.logCollectionStopped(view, viewModel)
+                    }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 275cfc5..dfabeea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -17,14 +17,13 @@
 package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
 
 import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH
-import com.android.settingslib.graph.SignalDrawable
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
-import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import kotlinx.coroutines.CoroutineScope
@@ -76,26 +75,6 @@
     constants: ConnectivityConstants,
     scope: CoroutineScope,
 ) : MobileIconViewModelCommon {
-    /** Whether or not to show the error state of [SignalDrawable] */
-    private val showExclamationMark: StateFlow<Boolean> =
-        combine(
-                iconInteractor.isDefaultDataEnabled,
-                iconInteractor.isDefaultConnectionFailed,
-                iconInteractor.isInService,
-            ) { isDefaultDataEnabled, isDefaultConnectionFailed, isInService ->
-                !isDefaultDataEnabled || isDefaultConnectionFailed || !isInService
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), true)
-
-    private val shownLevel: StateFlow<Int> =
-        combine(
-                iconInteractor.level,
-                iconInteractor.isInService,
-            ) { level, isInService ->
-                if (isInService) level else 0
-            }
-            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
-
     override val isVisible: StateFlow<Boolean> =
         if (!constants.hasDataCapabilities) {
                 flowOf(false)
@@ -123,40 +102,12 @@
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
-    override val icon: Flow<SignalIconModel> = run {
-        val initial =
-            SignalIconModel(
-                level = shownLevel.value,
-                numberOfLevels = iconInteractor.numberOfLevels.value,
-                showExclamationMark = showExclamationMark.value,
-                carrierNetworkChange = iconInteractor.carrierNetworkChangeActive.value,
-            )
-        combine(
-                shownLevel,
-                iconInteractor.numberOfLevels,
-                showExclamationMark,
-                iconInteractor.carrierNetworkChangeActive,
-            ) { shownLevel, numberOfLevels, showExclamationMark, carrierNetworkChange ->
-                SignalIconModel(
-                    shownLevel,
-                    numberOfLevels,
-                    showExclamationMark,
-                    carrierNetworkChange,
-                )
-            }
-            .distinctUntilChanged()
-            .logDiffsForTable(
-                iconInteractor.tableLogBuffer,
-                columnPrefix = "icon",
-                initialValue = initial,
-            )
-            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
-    }
+    override val icon: Flow<SignalIconModel> = iconInteractor.signalLevelIcon
 
     override val contentDescription: Flow<ContentDescription> = run {
         val initial = ContentDescription.Resource(PHONE_SIGNAL_STRENGTH[0])
-        shownLevel
-            .map { ContentDescription.Resource(PHONE_SIGNAL_STRENGTH[it]) }
+        iconInteractor.signalLevelIcon
+            .map { ContentDescription.Resource(PHONE_SIGNAL_STRENGTH[it.level]) }
             .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 216afb9..0f55910 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -20,7 +20,6 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.phone.StatusBarLocation
-import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -56,7 +55,6 @@
     private val airplaneModeInteractor: AirplaneModeInteractor,
     private val constants: ConnectivityConstants,
     @Application private val scope: CoroutineScope,
-    private val statusBarPipelineFlags: StatusBarPipelineFlags,
 ) {
     @VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
     @VisibleForTesting
@@ -101,7 +99,7 @@
         val common = commonViewModelForSub(subId)
         return LocationBasedMobileViewModel.viewModelForLocation(
             common,
-            mobileIconInteractorForSub(subId),
+            interactor.getMobileConnectionInteractorForSubId(subId),
             verboseLogger,
             location,
             scope,
@@ -112,7 +110,7 @@
         return mobileIconSubIdCache[subId]
             ?: MobileIconViewModel(
                     subId,
-                    mobileIconInteractorForSub(subId),
+                    interactor.getMobileConnectionInteractorForSubId(subId),
                     airplaneModeInteractor,
                     constants,
                     scope,
@@ -120,14 +118,6 @@
                 .also { mobileIconSubIdCache[subId] = it }
     }
 
-    @VisibleForTesting
-    fun mobileIconInteractorForSub(subId: Int): MobileIconInteractor {
-        return mobileIconInteractorSubIdCache[subId]
-            ?: interactor.createMobileConnectionInteractorForSubId(subId).also {
-                mobileIconInteractorSubIdCache[subId] = it
-            }
-    }
-
     private fun invalidateCaches(subIds: List<Int>) {
         val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
         subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/InternetTileBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/InternetTileBinder.kt
new file mode 100644
index 0000000..189dc40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/InternetTileBinder.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.binder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.coroutineScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.statusbar.pipeline.shared.ui.model.InternetTileModel
+import java.util.function.Consumer
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+
+/**
+ * Binds an [InternetTileModel] flow to a consumer for the internet tile to apply to its qs state
+ */
+object InternetTileBinder {
+    fun bind(
+        lifecycle: Lifecycle,
+        tileModelFlow: StateFlow<InternetTileModel>,
+        consumer: Consumer<InternetTileModel>
+    ) {
+        lifecycle.coroutineScope.launch {
+            lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
+                tileModelFlow.collect { consumer.accept(it) }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
new file mode 100644
index 0000000..327dd8d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.model
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.service.quicksettings.Tile
+import com.android.settingslib.graph.SignalDrawable
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.common.shared.model.Text.Companion.loadText
+import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.tileimpl.QSTileImpl
+
+/** Model describing the state that the QS Internet tile should be in. */
+sealed interface InternetTileModel {
+    val secondaryTitle: String?
+    val secondaryLabel: Text?
+    val iconId: Int?
+    val icon: QSTile.Icon?
+
+    fun applyTo(state: QSTile.SignalState, context: Context) {
+        if (secondaryLabel != null) {
+            state.secondaryLabel = secondaryLabel.loadText(context)
+        } else {
+            state.secondaryLabel = secondaryTitle
+        }
+
+        // inout indicators are unused
+        state.activityIn = false
+        state.activityOut = false
+
+        // To support both SignalDrawable and other icons, give priority to icons over IDs
+        if (icon != null) {
+            state.icon = icon
+        } else if (iconId != null) {
+            state.icon = QSTileImpl.ResourceIcon.get(iconId!!)
+        }
+
+        state.state =
+            if (this is Active) {
+                Tile.STATE_ACTIVE
+            } else {
+                Tile.STATE_INACTIVE
+            }
+    }
+
+    data class Active(
+        override val secondaryTitle: String? = null,
+        override val secondaryLabel: Text? = null,
+        override val iconId: Int? = null,
+        override val icon: QSTile.Icon? = null,
+    ) : InternetTileModel
+
+    data class Inactive(
+        override val secondaryTitle: String? = null,
+        override val secondaryLabel: Text? = null,
+        override val iconId: Int? = null,
+        override val icon: QSTile.Icon? = null,
+    ) : InternetTileModel
+}
+
+/**
+ * [QSTile.Icon]-compatible container class for us to marshal the compacted [SignalDrawable] state
+ * across to the internet tile.
+ */
+data class SignalIcon(val state: Int) : QSTile.Icon() {
+
+    override fun getDrawable(context: Context): Drawable {
+        val d = SignalDrawable(context)
+        d.setLevel(state)
+        return d
+    }
+
+    override fun toString(): String {
+        return String.format("SignalIcon[mState=0x%08x]", state)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt
new file mode 100644
index 0000000..b6f1677
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModel.kt
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+
+import android.content.Context
+import com.android.systemui.R
+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.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.ui.model.InternetTileModel
+import com.android.systemui.statusbar.pipeline.shared.ui.model.SignalIcon
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * View model for the quick settings [InternetTile]. This model exposes mainly a single flow of
+ * InternetTileModel objects, so that updating the tile is as simple as collecting on this state
+ * flow and then calling [QSTileImpl.refreshState]
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class InternetTileViewModel
+@Inject
+constructor(
+    airplaneModeRepository: AirplaneModeRepository,
+    connectivityRepository: ConnectivityRepository,
+    ethernetInteractor: EthernetInteractor,
+    mobileIconsInteractor: MobileIconsInteractor,
+    wifiInteractor: WifiInteractor,
+    private val context: Context,
+    @Application scope: CoroutineScope,
+) {
+    // Three symmetrical Flows that can be switched upon based on the value of
+    // [DefaultConnectionModel]
+    private val wifiIconFlow: Flow<InternetTileModel> =
+        wifiInteractor.wifiNetwork.flatMapLatest {
+            val wifiIcon = WifiIcon.fromModel(it, context, showHotspotInfo = true)
+            if (it is WifiNetworkModel.Active && wifiIcon is WifiIcon.Visible) {
+                flowOf(
+                    InternetTileModel.Active(
+                        secondaryTitle = removeDoubleQuotes(it.ssid),
+                        icon = ResourceIcon.get(wifiIcon.icon.res)
+                    )
+                )
+            } else {
+                notConnectedFlow
+            }
+        }
+
+    private val mobileDataContentName: Flow<CharSequence?> =
+        mobileIconsInteractor.activeDataIconInteractor.flatMapLatest {
+            if (it == null) {
+                flowOf(null)
+            } else {
+                combine(it.isRoaming, it.networkTypeIconGroup) { isRoaming, networkTypeIconGroup ->
+                    val cd = loadString(networkTypeIconGroup.contentDescription)
+                    if (isRoaming) {
+                        val roaming = context.getString(R.string.data_connection_roaming)
+                        if (cd != null) {
+                            context.getString(R.string.mobile_data_text_format, roaming, cd)
+                        } else {
+                            roaming
+                        }
+                    } else {
+                        cd
+                    }
+                }
+            }
+        }
+
+    private val mobileIconFlow: Flow<InternetTileModel> =
+        mobileIconsInteractor.activeDataIconInteractor.flatMapLatest {
+            if (it == null) {
+                notConnectedFlow
+            } else {
+                combine(
+                    it.networkName,
+                    it.signalLevelIcon,
+                    mobileDataContentName,
+                ) { networkNameModel, signalIcon, dataContentDescription ->
+                    InternetTileModel.Active(
+                        secondaryTitle =
+                            mobileDataContentConcat(networkNameModel.name, dataContentDescription),
+                        icon = SignalIcon(signalIcon.toSignalDrawableState()),
+                    )
+                }
+            }
+        }
+
+    private fun mobileDataContentConcat(
+        networkName: String?,
+        dataContentDescription: CharSequence?
+    ): String {
+        if (dataContentDescription == null) {
+            return networkName ?: ""
+        }
+        if (networkName == null) {
+            return dataContentDescription.toString()
+        }
+
+        return context.getString(
+            R.string.mobile_carrier_text_format,
+            networkName,
+            dataContentDescription
+        )
+    }
+
+    private fun loadString(resId: Int): String? =
+        if (resId > 0) {
+            context.getString(resId)
+        } else {
+            null
+        }
+
+    private val ethernetIconFlow: Flow<InternetTileModel> =
+        ethernetInteractor.icon.flatMapLatest {
+            if (it == null) {
+                notConnectedFlow
+            } else {
+                flowOf(
+                    InternetTileModel.Active(
+                        secondaryTitle = it.contentDescription.toString(),
+                        iconId = it.res
+                    )
+                )
+            }
+        }
+
+    private val notConnectedFlow: StateFlow<InternetTileModel> =
+        combine(
+                wifiInteractor.areNetworksAvailable,
+                airplaneModeRepository.isAirplaneMode,
+            ) { networksAvailable, isAirplaneMode ->
+                when {
+                    isAirplaneMode -> {
+                        InternetTileModel.Inactive(
+                            secondaryTitle = context.getString(R.string.status_bar_airplane),
+                            icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable)
+                        )
+                    }
+                    networksAvailable -> {
+                        InternetTileModel.Inactive(
+                            secondaryTitle =
+                                context.getString(R.string.quick_settings_networks_available),
+                            iconId = R.drawable.ic_qs_no_internet_available,
+                        )
+                    }
+                    else -> {
+                        NOT_CONNECTED_NETWORKS_UNAVAILABLE
+                    }
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), NOT_CONNECTED_NETWORKS_UNAVAILABLE)
+
+    /**
+     * Strict ordering of which repo is sending its data to the internet tile. Swaps between each of
+     * the interim providers (wifi, mobile, ethernet, or not-connected)
+     */
+    private val activeModelProvider: Flow<InternetTileModel> =
+        connectivityRepository.defaultConnections.flatMapLatest {
+            when {
+                it.ethernet.isDefault -> ethernetIconFlow
+                it.mobile.isDefault || it.carrierMerged.isDefault -> mobileIconFlow
+                it.wifi.isDefault -> wifiIconFlow
+                else -> notConnectedFlow
+            }
+        }
+
+    /** Consumable flow describing the correct state for the InternetTile */
+    val tileModel: StateFlow<InternetTileModel> =
+        activeModelProvider.stateIn(scope, SharingStarted.WhileSubscribed(), notConnectedFlow.value)
+
+    companion object {
+        val NOT_CONNECTED_NETWORKS_UNAVAILABLE =
+            InternetTileModel.Inactive(
+                secondaryLabel = Text.Resource(R.string.quick_settings_networks_unavailable),
+                iconId = R.drawable.ic_qs_no_internet_unavailable,
+            )
+
+        private fun removeDoubleQuotes(string: String?): String? {
+            if (string == null) return null
+            val length = string.length
+            return if (length > 1 && string[0] == '"' && string[length - 1] == '"') {
+                string.substring(1, length - 1)
+            } else string
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index b5b99a7..b22e09e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import kotlinx.coroutines.flow.StateFlow
 
 /** Provides data related to the wifi state. */
@@ -45,6 +46,12 @@
     val wifiActivity: StateFlow<DataActivityModel>
 
     /**
+     * The list of known wifi networks, per [WifiManager.scanResults]. This list is passively
+     * updated and does not trigger a scan.
+     */
+    val wifiScanResults: StateFlow<List<WifiScanEntry>>
+
+    /**
      * Returns true if the device is currently connected to a wifi network with a valid SSID and
      * false otherwise.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
index 80091ac..ca042e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcher.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -124,4 +125,9 @@
         activeRepo
             .flatMapLatest { it.wifiActivity }
             .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiActivity.value)
+
+    override val wifiScanResults: StateFlow<List<WifiScanEntry>> =
+        activeRepo
+            .flatMapLatest { it.wifiScanResults }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), realImpl.wifiScanResults.value)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
index 4b19c3a..152d181 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
@@ -55,6 +56,10 @@
         MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
     override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity
 
+    private val _wifiScanResults: MutableStateFlow<List<WifiScanEntry>> =
+        MutableStateFlow(emptyList())
+    override val wifiScanResults: StateFlow<List<WifiScanEntry>> = _wifiScanResults
+
     fun startProcessingCommands() {
         demoCommandJob =
             scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt
index 36c46a9..cfdbe4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/DisabledWifiRepository.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryViaTrackerLibDagger
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -49,6 +50,9 @@
     override val wifiActivity: StateFlow<DataActivityModel> =
         MutableStateFlow(ACTIVITY).asStateFlow()
 
+    override val wifiScanResults: StateFlow<List<WifiScanEntry>> =
+        MutableStateFlow<List<WifiScanEntry>>(emptyList()).asStateFlow()
+
     companion object {
         private val NETWORK = WifiNetworkModel.Unavailable
         private val ACTIVITY = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
index f1b98b3..67dd32f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryHelper.kt
@@ -16,15 +16,21 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
 
+import android.annotation.SuppressLint
+import android.net.wifi.ScanResult
 import android.net.wifi.WifiManager
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.toWifiDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import java.util.concurrent.Executor
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
@@ -64,6 +70,34 @@
             )
     }
 
+    /**
+     * Creates a flow that listens for new [ScanResult]s from [WifiManager]. Does not request a scan
+     */
+    fun createNetworkScanFlow(
+        wifiManager: WifiManager,
+        scope: CoroutineScope,
+        @Background dispatcher: CoroutineDispatcher,
+        inputLogger: () -> Unit,
+    ): StateFlow<List<WifiScanEntry>> {
+        return conflatedCallbackFlow {
+                val callback =
+                    object : WifiManager.ScanResultsCallback() {
+                        @SuppressLint("MissingPermission")
+                        override fun onScanResultsAvailable() {
+                            inputLogger.invoke()
+                            trySend(wifiManager.scanResults.toModel())
+                        }
+                    }
+
+                wifiManager.registerScanResultsCallback(dispatcher.asExecutor(), callback)
+
+                awaitClose { wifiManager.unregisterScanResultsCallback(callback) }
+            }
+            .stateIn(scope, SharingStarted.Eagerly, emptyList())
+    }
+
+    private fun List<ScanResult>.toModel(): List<WifiScanEntry> = map { WifiScanEntry(it.SSID) }
+
     // TODO(b/292534484): This print should only be done in [MessagePrinter] part of the log buffer.
     private fun prettyPrintActivity(activity: Int): String {
         return when (activity) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 7c7b58d..59ef884 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -48,6 +48,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryDagger
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -231,6 +232,14 @@
             logger::logActivity,
         )
 
+    override val wifiScanResults: StateFlow<List<WifiScanEntry>> =
+        WifiRepositoryHelper.createNetworkScanFlow(
+            wifiManager,
+            scope,
+            bgDispatcher,
+            logger::logScanResults
+        )
+
     companion object {
         // Start out with no known wifi network.
         // Note: [WifiStatusTracker] (the old implementation of connectivity logic) does do an
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
index d4f40dd..9b404f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLib.kt
@@ -23,6 +23,7 @@
 import androidx.lifecycle.LifecycleRegistry
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -42,6 +43,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_STATE_DEFAULT
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive.toHotspotDeviceType
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import com.android.wifitrackerlib.HotspotNetworkEntry
 import com.android.wifitrackerlib.MergedCarrierEntry
 import com.android.wifitrackerlib.WifiEntry
@@ -51,6 +53,7 @@
 import com.android.wifitrackerlib.WifiPickerTracker
 import java.util.concurrent.Executor
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.SharingStarted
@@ -73,6 +76,7 @@
     featureFlags: FeatureFlags,
     @Application private val scope: CoroutineScope,
     @Main private val mainExecutor: Executor,
+    @Background private val bgDispatcher: CoroutineDispatcher,
     private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
     private val wifiManager: WifiManager,
     @WifiTrackerLibInputLog private val inputLogger: LogBuffer,
@@ -300,6 +304,14 @@
             this::logActivity,
         )
 
+    override val wifiScanResults: StateFlow<List<WifiScanEntry>> =
+        WifiRepositoryHelper.createNetworkScanFlow(
+            wifiManager,
+            scope,
+            bgDispatcher,
+            this::logScanResults,
+        )
+
     private fun logOnWifiEntriesChanged(connectedEntry: WifiEntry?) {
         inputLogger.log(
             TAG,
@@ -322,6 +334,9 @@
         inputLogger.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "onActivityChanged: $str1" })
     }
 
+    private fun logScanResults() =
+        inputLogger.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" })
+
     /**
      * Data class storing all the information fetched from [WifiPickerTracker].
      *
@@ -345,6 +360,7 @@
         private val featureFlags: FeatureFlags,
         @Application private val scope: CoroutineScope,
         @Main private val mainExecutor: Executor,
+        @Background private val bgDispatcher: CoroutineDispatcher,
         private val wifiPickerTrackerFactory: WifiPickerTrackerFactory,
         @WifiTrackerLibInputLog private val inputLogger: LogBuffer,
         @WifiTrackerLibTableLog private val wifiTrackerLibTableLogBuffer: TableLogBuffer,
@@ -354,6 +370,7 @@
                 featureFlags,
                 scope,
                 mainExecutor,
+                bgDispatcher,
                 wifiPickerTrackerFactory,
                 wifiManager,
                 inputLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index 1a41abf..110e339 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -17,15 +17,21 @@
 package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
 
 /**
  * The business logic layer for the wifi icon.
@@ -54,6 +60,9 @@
 
     /** True if we're configured to force-hide the wifi icon and false otherwise. */
     val isForceHidden: Flow<Boolean>
+
+    /** True if there are networks available other than the currently-connected one */
+    val areNetworksAvailable: StateFlow<Boolean>
 }
 
 @SysUISingleton
@@ -62,6 +71,7 @@
 constructor(
     connectivityRepository: ConnectivityRepository,
     wifiRepository: WifiRepository,
+    @Application scope: CoroutineScope,
 ) : WifiInteractor {
 
     override val ssid: Flow<String?> =
@@ -91,4 +101,26 @@
 
     override val isForceHidden: Flow<Boolean> =
         connectivityRepository.forceHiddenSlots.map { it.contains(ConnectivitySlot.WIFI) }
+
+    override val areNetworksAvailable: StateFlow<Boolean> =
+        combine(
+                wifiNetwork,
+                wifiRepository.wifiScanResults,
+            ) { currentNetwork, scanResults ->
+                // We consider networks to be available if the scan results list contains networks
+                // other than the one that is currently connected
+                if (scanResults.isEmpty()) {
+                    false
+                } else if (currentNetwork !is WifiNetworkModel.Active) {
+                    true
+                } else {
+                    anyNonMatchingNetworkExists(currentNetwork, scanResults)
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    private fun anyNonMatchingNetworkExists(
+        currentNetwork: WifiNetworkModel.Active,
+        availableNetworks: List<WifiScanEntry>
+    ): Boolean = availableNetworks.firstOrNull { it.ssid != currentNetwork.ssid } != null
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
index f244376..b76bb51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiInputLogger.kt
@@ -59,6 +59,8 @@
     fun logActivity(activity: String) {
         buffer.log(TAG, LogLevel.DEBUG, { str1 = activity }, { "Activity: $str1" })
     }
+
+    fun logScanResults() = buffer.log(TAG, LogLevel.DEBUG, {}, { "onScanResultsAvailable" })
 }
 
 private const val TAG = "WifiInputLog"
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiScanEntry.kt
similarity index 71%
rename from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiScanEntry.kt
index 24064b1..d4a5a0e 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiScanEntry.kt
@@ -14,13 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.scene.ui.composable
+package com.android.systemui.statusbar.pipeline.wifi.shared.model
 
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
-
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
-}
+/**
+ * Represents a single entry in the scan results callback. Use the [ssid] field to check against
+ * other networks
+ */
+data class WifiScanEntry(val ssid: String)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt
index 094bcf9..668c5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/model/WifiIcon.kt
@@ -17,10 +17,18 @@
 package com.android.systemui.statusbar.pipeline.wifi.ui.model
 
 import android.annotation.DrawableRes
+import android.content.Context
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+import com.android.systemui.R
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.log.table.Diffable
 import com.android.systemui.log.table.TableRowLogger
+import com.android.systemui.statusbar.connectivity.WifiIcons
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 
 /** Represents the various states of the wifi icon. */
 sealed interface WifiIcon : Diffable<WifiIcon> {
@@ -34,7 +42,7 @@
      * description.
      */
     class Visible(
-        @DrawableRes res: Int,
+        @DrawableRes val res: Int,
         val contentDescription: ContentDescription.Loaded,
     ) : WifiIcon {
         val icon = Icon.Resource(res, contentDescription)
@@ -51,6 +59,84 @@
     override fun logFull(row: TableRowLogger) {
         row.logChange(COL_ICON, toString())
     }
+
+    companion object {
+        @StringRes
+        @VisibleForTesting
+        internal val NO_INTERNET = R.string.data_connection_no_internet
+
+        /**
+         * Mapping from a [WifiNetworkModel] to the appropriate [WifiIcon].
+         *
+         * @param showHotspotInfo true if the wifi icon should represent the hotspot device (if it
+         *   exists) and false if the wifi icon should only ever show the wifi level and *not* the
+         *   hotspot device.
+         */
+        fun fromModel(
+            model: WifiNetworkModel,
+            context: Context,
+            showHotspotInfo: Boolean,
+        ): WifiIcon =
+            when (model) {
+                is WifiNetworkModel.Unavailable -> Hidden
+                is WifiNetworkModel.Invalid -> Hidden
+                is WifiNetworkModel.CarrierMerged -> Hidden
+                is WifiNetworkModel.Inactive ->
+                    Visible(
+                        res = WifiIcons.WIFI_NO_NETWORK,
+                        ContentDescription.Loaded(
+                            "${context.getString(WIFI_NO_CONNECTION)},${context.getString(
+                                NO_INTERNET
+                            )}"
+                        )
+                    )
+                is WifiNetworkModel.Active -> {
+                    val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[model.level])
+                    val contentDescription =
+                        ContentDescription.Loaded(
+                            if (model.isValidated) {
+                                (levelDesc)
+                            } else {
+                                "$levelDesc,${context.getString(NO_INTERNET)}"
+                            }
+                        )
+                    Visible(model.toIcon(showHotspotInfo), contentDescription)
+                }
+            }
+
+        @DrawableRes
+        private fun WifiNetworkModel.Active.toIcon(showHotspotInfo: Boolean): Int {
+            return if (!showHotspotInfo) {
+                this.toBasicIcon()
+            } else {
+                when (this.hotspotDeviceType) {
+                    WifiNetworkModel.HotspotDeviceType.NONE -> this.toBasicIcon()
+                    WifiNetworkModel.HotspotDeviceType.TABLET ->
+                        com.android.settingslib.R.drawable.ic_hotspot_tablet
+                    WifiNetworkModel.HotspotDeviceType.LAPTOP ->
+                        com.android.settingslib.R.drawable.ic_hotspot_laptop
+                    WifiNetworkModel.HotspotDeviceType.WATCH ->
+                        com.android.settingslib.R.drawable.ic_hotspot_watch
+                    WifiNetworkModel.HotspotDeviceType.AUTO ->
+                        com.android.settingslib.R.drawable.ic_hotspot_auto
+                    // Use phone as the default drawable
+                    WifiNetworkModel.HotspotDeviceType.PHONE,
+                    WifiNetworkModel.HotspotDeviceType.UNKNOWN,
+                    WifiNetworkModel.HotspotDeviceType.INVALID ->
+                        com.android.settingslib.R.drawable.ic_hotspot_phone
+                }
+            }
+        }
+
+        @DrawableRes
+        private fun WifiNetworkModel.Active.toBasicIcon(): Int {
+            return if (this.isValidated) {
+                WifiIcons.WIFI_FULL_ICONS[this.level]
+            } else {
+                WifiIcons.WIFI_NO_INTERNET_ICONS[this.level]
+            }
+        }
+    }
 }
 
 private const val COL_ICON = "icon"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index d9c2144..d099c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -17,19 +17,10 @@
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
 import android.content.Context
-import androidx.annotation.StringRes
-import androidx.annotation.VisibleForTesting
-import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
-import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
-import com.android.systemui.R
-import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
-import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
-import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
-import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
 import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule.Companion.FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON
 import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
@@ -75,39 +66,6 @@
     @Application private val scope: CoroutineScope,
     wifiConstants: WifiConstants,
 ) : WifiViewModelCommon {
-    /** Returns the icon to use based on the given network. */
-    private fun WifiNetworkModel.icon(): WifiIcon {
-        return when (this) {
-            is WifiNetworkModel.Unavailable -> WifiIcon.Hidden
-            is WifiNetworkModel.Invalid -> WifiIcon.Hidden
-            is WifiNetworkModel.CarrierMerged -> WifiIcon.Hidden
-            is WifiNetworkModel.Inactive ->
-                WifiIcon.Visible(
-                    res = WIFI_NO_NETWORK,
-                    ContentDescription.Loaded(
-                        "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
-                    )
-                )
-            is WifiNetworkModel.Active -> {
-                val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
-                when {
-                    this.isValidated ->
-                        WifiIcon.Visible(
-                            WIFI_FULL_ICONS[this.level],
-                            ContentDescription.Loaded(levelDesc),
-                        )
-                    else ->
-                        WifiIcon.Visible(
-                            WIFI_NO_INTERNET_ICONS[this.level],
-                            ContentDescription.Loaded(
-                                "$levelDesc,${context.getString(NO_INTERNET)}"
-                            ),
-                        )
-                }
-            }
-        }
-    }
-
     override val wifiIcon: StateFlow<WifiIcon> =
         combine(
                 interactor.isEnabled,
@@ -119,7 +77,8 @@
                     return@combine WifiIcon.Hidden
                 }
 
-                val icon = wifiNetwork.icon()
+                // Don't show any hotspot info in the status bar.
+                val icon = WifiIcon.fromModel(wifiNetwork, context, showHotspotInfo = false)
 
                 return@combine when {
                     isDefault -> icon
@@ -186,10 +145,4 @@
         airplaneModeViewModel.isAirplaneModeIconVisible
 
     override val isSignalSpacerVisible: Flow<Boolean> = shouldShowSignalSpacerProvider.get()
-
-    companion object {
-        @StringRes
-        @VisibleForTesting
-        internal val NO_INTERNET = R.string.data_connection_no_internet
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
index 1212585..feef029 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpUtil.java
@@ -16,9 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
 import android.view.View;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.util.Compile;
 
 /**
  * A class of utility static methods for heads up notifications.
@@ -26,12 +32,18 @@
 public final class HeadsUpUtil {
     private static final int TAG_CLICKED_NOTIFICATION = R.id.is_clicked_heads_up_tag;
 
+    private static final String LOG_TAG = "HeadsUpUtil";
+    private static final boolean LOG_DEBUG = Compile.IS_DEBUG && Log.isLoggable(LOG_TAG, Log.DEBUG);
+
     /**
      * Set the given view as clicked or not-clicked.
      * @param view The view to be set the flag to.
      * @param clicked True to set as clicked. False to not-clicked.
      */
     public static void setNeedsHeadsUpDisappearAnimationAfterClick(View view, boolean clicked) {
+        if (LOG_DEBUG) {
+            logTagClickedNotificationChanged(view, clicked);
+        }
         view.setTag(TAG_CLICKED_NOTIFICATION, clicked ? true : null);
     }
 
@@ -44,4 +56,36 @@
         Boolean clicked = (Boolean) view.getTag(TAG_CLICKED_NOTIFICATION);
         return clicked != null && clicked;
     }
+
+    private static void logTagClickedNotificationChanged(@Nullable View view, boolean isClicked) {
+        if (view == null) {
+            return;
+        }
+
+        final boolean wasClicked = isClickedHeadsUpNotification(view);
+        if (isClicked == wasClicked) {
+            return;
+        }
+
+        Log.d(LOG_TAG, getViewKey(view) + ": TAG_CLICKED_NOTIFICATION set to " + isClicked);
+    }
+
+    private static @NonNull String getViewKey(@NonNull View view) {
+        if (!(view instanceof ExpandableNotificationRow)) {
+            return "(not a row)";
+        }
+
+        final ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+        final NotificationEntry entry = row.getEntry();
+        if (entry == null) {
+            return "(null entry)";
+        }
+
+        final String key = entry.getKey();
+        if (key == null) {
+            return "(null key)";
+        }
+
+        return key;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index c91313ad..6afa525 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -126,12 +126,14 @@
         withDeps.featureFlags.apply {
             set(Flags.REGION_SAMPLING, false)
             set(Flags.DOZING_MIGRATION_1, false)
+            set(Flags.FACE_AUTH_REFACTOR, false)
         }
         underTest =
             ClockEventController(
                 withDeps.keyguardInteractor,
                 KeyguardTransitionInteractorFactory.create(
                         scope = TestScope().backgroundScope,
+                        featureFlags = withDeps.featureFlags,
                     )
                     .keyguardTransitionInteractor,
                 broadcastDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index 3a94730..e1b608f 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -16,15 +16,16 @@
 
 package com.android.keyguard
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.inputmethod.InputMethodManager
 import android.widget.EditText
 import android.widget.ImageView
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.R
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -45,7 +46,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPasswordViewControllerTest : SysuiTestCase() {
     @Mock private lateinit var keyguardPasswordView: KeyguardPasswordView
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 1acd676..93048a5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -16,15 +16,16 @@
 
 package com.android.keyguard
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.R
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
@@ -52,7 +53,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPatternViewControllerTest : SysuiTestCase() {
     private lateinit var mKeyguardPatternView: KeyguardPatternView
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index efe1955..2b90e7c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -22,16 +22,17 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.R;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.classifier.FalsingCollectorFake;
@@ -46,7 +47,8 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 80fd721..61acacd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -16,16 +16,17 @@
 
 package com.android.keyguard
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode
 import com.android.systemui.R
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
@@ -52,7 +53,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardPinViewControllerTest : SysuiTestCase() {
 
@@ -175,7 +177,8 @@
 
     private fun getPinTopGuideline(): Float {
         val cs = ConstraintSet()
-        val container = objectKeyguardPINView.requireViewById(R.id.pin_container) as ConstraintLayout
+        val container =
+            objectKeyguardPINView.requireViewById(R.id.pin_container) as ConstraintLayout
         cs.clone(container)
         return cs.getConstraint(R.id.pin_pad_top_guideline).layout.guidePercent
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 80172a1..5da919b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -21,7 +21,6 @@
 import android.hardware.biometrics.BiometricOverlayConstants
 import android.media.AudioManager
 import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.testing.TestableResources
 import android.view.Gravity
@@ -30,6 +29,7 @@
 import android.view.View
 import android.view.WindowInsetsController
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
@@ -37,6 +37,7 @@
 import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode
 import com.android.systemui.R
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
 import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate
@@ -96,7 +97,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
 
@@ -189,7 +191,6 @@
 
         featureFlags = FakeFeatureFlags()
         featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
-        featureFlags.set(Flags.SCENE_CONTAINER, false)
         featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false)
         featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
 
@@ -242,6 +243,7 @@
                 falsingManager,
                 userSwitcherController,
                 featureFlags,
+                sceneTestUtils.sceneContainerFlags,
                 globalSettings,
                 sessionTracker,
                 Optional.of(sideFpsController),
@@ -620,51 +622,6 @@
         configurationListenerArgumentCaptor.value.onUiModeChanged()
         verify(view).reloadColors()
     }
-    @Test
-    fun onOrientationChanged_landscapeKeyguardFlagDisabled_blockReinflate() {
-        featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
-
-        // Run onOrientationChanged
-        val configurationListenerArgumentCaptor =
-            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
-        underTest.onViewAttached()
-        verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
-        clearInvocations(viewFlipperController)
-        configurationListenerArgumentCaptor.value.onOrientationChanged(
-            Configuration.ORIENTATION_LANDSCAPE
-        )
-        // Verify view is reinflated when flag is on
-        verify(viewFlipperController, never()).clearViews()
-        verify(viewFlipperController, never())
-            .asynchronouslyInflateView(
-                eq(SecurityMode.PIN),
-                any(),
-                onViewInflatedCallbackArgumentCaptor.capture()
-            )
-    }
-
-    @Test
-    fun onOrientationChanged_landscapeKeyguardFlagEnabled_doesReinflate() {
-        featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true)
-
-        // Run onOrientationChanged
-        val configurationListenerArgumentCaptor =
-            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
-        underTest.onViewAttached()
-        verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
-        clearInvocations(viewFlipperController)
-        configurationListenerArgumentCaptor.value.onOrientationChanged(
-            Configuration.ORIENTATION_LANDSCAPE
-        )
-        // Verify view is reinflated when flag is on
-        verify(viewFlipperController).clearViews()
-        verify(viewFlipperController)
-            .asynchronouslyInflateView(
-                eq(SecurityMode.PIN),
-                any(),
-                onViewInflatedCallbackArgumentCaptor.capture()
-            )
-    }
 
     @Test
     fun hasDismissActions() {
@@ -800,8 +757,6 @@
     @Test
     fun dismissesKeyguard_whenSceneChangesToGone() =
         sceneTestUtils.testScope.runTest {
-            featureFlags.set(Flags.SCENE_CONTAINER, true)
-
             // Upon init, we have never dismisses the keyguard.
             underTest.onInit()
             runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index f6450a4..3e330d65 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -44,7 +44,6 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Insets;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
 import android.view.View;
@@ -54,9 +53,11 @@
 import android.window.OnBackAnimationCallback;
 
 import androidx.constraintlayout.widget.ConstraintSet;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.R;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingA11yDelegate;
 import com.android.systemui.plugins.FalsingManager;
@@ -75,7 +76,8 @@
 import java.util.ArrayList;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityContainerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
index 64e1458..19bc818 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -25,17 +25,18 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.view.WindowInsetsController;
 
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.systemui.R;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.flags.FeatureFlags;
 
@@ -49,7 +50,8 @@
 import org.mockito.junit.MockitoRule;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase {
 
@@ -138,11 +140,6 @@
 
     @Test
     public void asynchronouslyInflateView_setNeedsInput() {
-        when(mKeyguardSecurityViewControllerFactory.create(
-               any(), any(SecurityMode.class),
-                any(KeyguardSecurityCallback.class)))
-                .thenReturn(mKeyguardInputViewController);
-
         ArgumentCaptor<AsyncLayoutInflater.OnInflateFinishedListener> argumentCaptor =
                 ArgumentCaptor.forClass(AsyncLayoutInflater.OnInflateFinishedListener.class);
         mKeyguardSecurityViewFlipperController.asynchronouslyInflateView(SecurityMode.PIN,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
index 291dda25..4db5f35 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt
@@ -18,13 +18,14 @@
 
 import android.telephony.PinResult
 import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.R
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -43,7 +44,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardSimPinViewControllerTest : SysuiTestCase() {
     private lateinit var simPinView: KeyguardSimPinView
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
index 626faa6..47ff3b9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSimPukViewControllerTest.kt
@@ -18,13 +18,14 @@
 
 import android.telephony.PinResult
 import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.R
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.flags.FakeFeatureFlags
@@ -39,7 +40,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class KeyguardSimPukViewControllerTest : SysuiTestCase() {
     private lateinit var simPukView: KeyguardSimPukView
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index b9e3f14..09ff546 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -24,7 +24,6 @@
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -148,7 +147,6 @@
         mFeatureFlags.set(MIGRATE_LOCK_ICON, false);
         mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
         mUnderTest = new LockIconViewController(
-                mLockIconView,
                 mStatusBarStateController,
                 mKeyguardUpdateMonitor,
                 mKeyguardViewController,
@@ -167,7 +165,8 @@
                                 .getKeyguardTransitionInteractor(),
                 KeyguardInteractorFactory.create(mFeatureFlags).getKeyguardInteractor(),
                 mFeatureFlags,
-                mPrimaryBouncerInteractor
+                mPrimaryBouncerInteractor,
+                mContext
         );
     }
 
@@ -228,9 +227,6 @@
 
     protected void init(boolean useMigrationFlag) {
         mFeatureFlags.set(DOZING_MIGRATION_1, useMigrationFlag);
-        mUnderTest.init();
-
-        verify(mLockIconView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
-        mAttachCaptor.getValue().onViewAttachedToWindow(mLockIconView);
+        mUnderTest.setLockIconView(mLockIconView);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
index 45021ba..979fc83 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
@@ -52,6 +52,12 @@
 @TestableLooper.RunWithLooper
 public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
 
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        when(mLockIconView.isAttachedToWindow()).thenReturn(true);
+    }
+
     @Test
     public void testUpdateFingerprintLocationOnInit() {
         // GIVEN fp sensor location is available pre-attached
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 b100336..f9830b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -71,6 +71,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -163,6 +164,204 @@
     }
 
     @Test
+    public void startListening_fetchesCurrentActive_none() {
+        when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS))
+                .thenReturn(List.of());
+
+        mController.setListening(true);
+
+        assertThat(mController.getActiveAppOps()).isEmpty();
+    }
+
+    /** Regression test for b/294104969. */
+    @Test
+    public void startListening_fetchesCurrentActive_oneActive() {
+        AppOpsManager.PackageOps packageOps = createPackageOp(
+                "package.test",
+                /* packageUid= */ 2,
+                AppOpsManager.OPSTR_FINE_LOCATION,
+                /* isRunning= */ true);
+        when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS))
+                .thenReturn(List.of(packageOps));
+
+        // WHEN we start listening
+        mController.setListening(true);
+
+        // THEN the active list has the op
+        List<AppOpItem> list = mController.getActiveAppOps();
+        assertEquals(1, list.size());
+        AppOpItem first = list.get(0);
+        assertThat(first.getPackageName()).isEqualTo("package.test");
+        assertThat(first.getUid()).isEqualTo(2);
+        assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION);
+    }
+
+    @Test
+    public void startListening_fetchesCurrentActive_multiplePackages() {
+        AppOpsManager.PackageOps packageOps1 = createPackageOp(
+                "package.one",
+                /* packageUid= */ 1,
+                AppOpsManager.OPSTR_FINE_LOCATION,
+                /* isRunning= */ true);
+        AppOpsManager.PackageOps packageOps2 = createPackageOp(
+                "package.two",
+                /* packageUid= */ 2,
+                AppOpsManager.OPSTR_FINE_LOCATION,
+                /* isRunning= */ false);
+        AppOpsManager.PackageOps packageOps3 = createPackageOp(
+                "package.three",
+                /* packageUid= */ 3,
+                AppOpsManager.OPSTR_FINE_LOCATION,
+                /* isRunning= */ true);
+        when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS))
+                .thenReturn(List.of(packageOps1, packageOps2, packageOps3));
+
+        // WHEN we start listening
+        mController.setListening(true);
+
+        // THEN the active list has the ops
+        List<AppOpItem> list = mController.getActiveAppOps();
+        assertEquals(2, list.size());
+
+        AppOpItem item0 = list.get(0);
+        assertThat(item0.getPackageName()).isEqualTo("package.one");
+        assertThat(item0.getUid()).isEqualTo(1);
+        assertThat(item0.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION);
+
+        AppOpItem item1 = list.get(1);
+        assertThat(item1.getPackageName()).isEqualTo("package.three");
+        assertThat(item1.getUid()).isEqualTo(3);
+        assertThat(item1.getCode()).isEqualTo(AppOpsManager.OP_FINE_LOCATION);
+    }
+
+    @Test
+    public void startListening_fetchesCurrentActive_multipleEntries() {
+        AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class);
+        when(packageOps.getUid()).thenReturn(1);
+        when(packageOps.getPackageName()).thenReturn("package.one");
+
+        // Entry 1
+        AppOpsManager.OpEntry entry1 = mock(AppOpsManager.OpEntry.class);
+        when(entry1.getOpStr()).thenReturn(AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE);
+        AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed1.isRunning()).thenReturn(true);
+        when(entry1.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed1));
+        // Entry 2
+        AppOpsManager.OpEntry entry2 = mock(AppOpsManager.OpEntry.class);
+        when(entry2.getOpStr()).thenReturn(AppOpsManager.OPSTR_CAMERA);
+        AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed2.isRunning()).thenReturn(true);
+        when(entry2.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed2));
+        // Entry 3
+        AppOpsManager.OpEntry entry3 = mock(AppOpsManager.OpEntry.class);
+        when(entry3.getOpStr()).thenReturn(AppOpsManager.OPSTR_FINE_LOCATION);
+        AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed3.isRunning()).thenReturn(false);
+        when(entry3.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed3));
+
+        when(packageOps.getOps()).thenReturn(List.of(entry1, entry2, entry3));
+        when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS))
+                .thenReturn(List.of(packageOps));
+
+        // WHEN we start listening
+        mController.setListening(true);
+
+        // THEN the active list has the ops
+        List<AppOpItem> list = mController.getActiveAppOps();
+        assertEquals(2, list.size());
+
+        AppOpItem first = list.get(0);
+        assertThat(first.getPackageName()).isEqualTo("package.one");
+        assertThat(first.getUid()).isEqualTo(1);
+        assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_PHONE_CALL_MICROPHONE);
+
+        AppOpItem second = list.get(1);
+        assertThat(second.getPackageName()).isEqualTo("package.one");
+        assertThat(second.getUid()).isEqualTo(1);
+        assertThat(second.getCode()).isEqualTo(AppOpsManager.OP_CAMERA);
+    }
+
+    @Test
+    public void startListening_fetchesCurrentActive_multipleAttributes() {
+        AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class);
+        when(packageOps.getUid()).thenReturn(1);
+        when(packageOps.getPackageName()).thenReturn("package.one");
+        AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class);
+        when(entry.getOpStr()).thenReturn(AppOpsManager.OPSTR_RECORD_AUDIO);
+
+        AppOpsManager.AttributedOpEntry attributed1 = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed1.isRunning()).thenReturn(false);
+        AppOpsManager.AttributedOpEntry attributed2 = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed2.isRunning()).thenReturn(true);
+        AppOpsManager.AttributedOpEntry attributed3 = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed3.isRunning()).thenReturn(true);
+        when(entry.getAttributedOpEntries()).thenReturn(
+                Map.of("attr1", attributed1, "attr2", attributed2, "attr3", attributed3));
+
+        when(packageOps.getOps()).thenReturn(List.of(entry));
+        when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS))
+                .thenReturn(List.of(packageOps));
+
+        // WHEN we start listening
+        mController.setListening(true);
+
+        // THEN the active list has the ops
+        List<AppOpItem> list = mController.getActiveAppOps();
+        // Multiple attributes get merged into one entry in the active ops
+        assertEquals(1, list.size());
+
+        AppOpItem first = list.get(0);
+        assertThat(first.getPackageName()).isEqualTo("package.one");
+        assertThat(first.getUid()).isEqualTo(1);
+        assertThat(first.getCode()).isEqualTo(AppOpsManager.OP_RECORD_AUDIO);
+    }
+
+    /** Regression test for b/294104969. */
+    @Test
+    public void addCallback_existingCallbacksNotifiedOfCurrentActive() {
+        AppOpsManager.PackageOps packageOps1 = createPackageOp(
+                "package.one",
+                /* packageUid= */ 1,
+                AppOpsManager.OPSTR_FINE_LOCATION,
+                /* isRunning= */ true);
+        AppOpsManager.PackageOps packageOps2 = createPackageOp(
+                "package.two",
+                /* packageUid= */ 2,
+                AppOpsManager.OPSTR_RECORD_AUDIO,
+                /* isRunning= */ true);
+        AppOpsManager.PackageOps packageOps3 = createPackageOp(
+                "package.three",
+                /* packageUid= */ 3,
+                AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE,
+                /* isRunning= */ true);
+        when(mAppOpsManager.getPackagesForOps(AppOpsControllerImpl.OPS))
+                .thenReturn(List.of(packageOps1, packageOps2, packageOps3));
+
+        // WHEN we start listening
+        mController.addCallback(
+                new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION},
+                mCallback);
+        mTestableLooper.processAllMessages();
+
+        // THEN the callback is notified of the current active ops it cares about
+        verify(mCallback).onActiveStateChanged(
+                AppOpsManager.OP_FINE_LOCATION,
+                /* uid= */ 1,
+                "package.one",
+                true);
+        verify(mCallback).onActiveStateChanged(
+                AppOpsManager.OP_RECORD_AUDIO,
+                /* uid= */ 2,
+                "package.two",
+                true);
+        verify(mCallback, never()).onActiveStateChanged(
+                AppOpsManager.OP_PHONE_CALL_MICROPHONE,
+                /* uid= */ 3,
+                "package.three",
+                true);
+    }
+
+    @Test
     public void addCallback_includedCode() {
         mController.addCallback(
                 new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION},
@@ -772,6 +971,22 @@
         assertFalse(list.get(1).isDisabled());
     }
 
+    private AppOpsManager.PackageOps createPackageOp(
+            String packageName, int packageUid, String opStr, boolean isRunning) {
+        AppOpsManager.PackageOps packageOps = mock(AppOpsManager.PackageOps.class);
+        when(packageOps.getPackageName()).thenReturn(packageName);
+        when(packageOps.getUid()).thenReturn(packageUid);
+        AppOpsManager.OpEntry entry = mock(AppOpsManager.OpEntry.class);
+        when(entry.getOpStr()).thenReturn(opStr);
+        AppOpsManager.AttributedOpEntry attributed = mock(AppOpsManager.AttributedOpEntry.class);
+        when(attributed.isRunning()).thenReturn(isRunning);
+
+        when(packageOps.getOps()).thenReturn(Collections.singletonList(entry));
+        when(entry.getAttributedOpEntries()).thenReturn(Map.of("tag", attributed));
+
+        return packageOps;
+    }
+
     private class TestHandler extends AppOpsControllerImpl.H {
         TestHandler(Looper looper) {
             mController.super(looper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
index 88c710a..ddb482f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/back/domain/interactor/BackActionInteractorTest.kt
@@ -16,18 +16,46 @@
 
 package com.android.systemui.back.domain.interactor
 
+import android.view.ViewRootImpl
+import android.window.BackEvent
+import android.window.BackEvent.EDGE_LEFT
+import android.window.OnBackAnimationCallback
+import android.window.OnBackInvokedCallback
+import android.window.OnBackInvokedDispatcher
+import android.window.WindowOnBackInvokedDispatcher
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.QuickSettingsController
 import com.android.systemui.shade.ShadeController
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.HeadsUpManager
+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.eq
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -41,7 +69,12 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
 class BackActionInteractorTest : SysuiTestCase() {
+    private val testScope = TestScope()
+    private val featureFlags = FakeFeatureFlags()
+    private val executor = FakeExecutor(FakeSystemClock())
+
     @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
 
     @Mock private lateinit var statusBarStateController: StatusBarStateController
@@ -49,18 +82,42 @@
     @Mock private lateinit var shadeController: ShadeController
     @Mock private lateinit var qsController: QuickSettingsController
     @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
+    @Mock private lateinit var windowRootView: WindowRootView
+    @Mock private lateinit var viewRootImpl: ViewRootImpl
+    @Mock private lateinit var onBackInvokedDispatcher: WindowOnBackInvokedDispatcher
+    @Mock private lateinit var iStatusBarService: IStatusBarService
+    @Mock private lateinit var headsUpManager: HeadsUpManager
 
-    private lateinit var backActionInteractor: BackActionInteractor
+    private val keyguardRepository = FakeKeyguardRepository()
+    private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor by lazy {
+        WindowRootViewVisibilityInteractor(
+            testScope.backgroundScope,
+            WindowRootViewVisibilityRepository(iStatusBarService, executor),
+            keyguardRepository,
+            headsUpManager,
+        )
+    }
 
-    @Before
-    fun setup() {
-        backActionInteractor =
-            BackActionInteractor(
+    private val backActionInteractor: BackActionInteractor by lazy {
+        BackActionInteractor(
+                testScope.backgroundScope,
                 statusBarStateController,
                 statusBarKeyguardViewManager,
                 shadeController,
+                notificationShadeWindowController,
+                windowRootViewVisibilityInteractor,
+                featureFlags,
             )
-        backActionInteractor.setup(qsController, shadeViewController)
+            .apply { this.setup(qsController, shadeViewController) }
+    }
+
+    @Before
+    fun setUp() {
+        featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, false)
+        whenever(notificationShadeWindowController.windowRootView).thenReturn(windowRootView)
+        whenever(windowRootView.viewRootImpl).thenReturn(viewRootImpl)
+        whenever(viewRootImpl.onBackInvokedDispatcher).thenReturn(onBackInvokedDispatcher)
     }
 
     @Test
@@ -117,4 +174,139 @@
         verify(statusBarKeyguardViewManager, never()).onBackPressed()
         verify(shadeViewController, never()).animateCollapseQs(anyBoolean())
     }
+
+    @Test
+    fun shadeVisibleAndDeviceAwake_callbackRegistered() {
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+
+        testScope.runCurrent()
+
+        verify(onBackInvokedDispatcher)
+            .registerOnBackInvokedCallback(eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT), any())
+    }
+
+    @Test
+    fun noWindowRootView_noCrashAttemptingCallbackRegistration() {
+        whenever(notificationShadeWindowController.windowRootView).thenReturn(null)
+
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+
+        testScope.runCurrent()
+        // No assert necessary, just testing no crash
+    }
+
+    @Test
+    fun shadeNotVisible_callbackUnregistered() {
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        val callback = getBackInvokedCallback()
+
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false)
+        testScope.runCurrent()
+
+        verify(onBackInvokedDispatcher).unregisterOnBackInvokedCallback(callback)
+    }
+
+    @Test
+    fun deviceAsleep_callbackUnregistered() {
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        val callback = getBackInvokedCallback()
+
+        setWakefulness(WakefulnessState.ASLEEP)
+        testScope.runCurrent()
+
+        verify(onBackInvokedDispatcher).unregisterOnBackInvokedCallback(callback)
+    }
+
+    @Test
+    fun animationFlagOff_onBackInvoked_keyguardNotified() {
+        backActionInteractor.start()
+        featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, false)
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        val callback = getBackInvokedCallback()
+        whenever(statusBarKeyguardViewManager.canHandleBackPressed()).thenReturn(true)
+
+        callback.onBackInvoked()
+
+        verify(statusBarKeyguardViewManager).onBackPressed()
+    }
+
+    @Test
+    fun animationFlagOn_onBackInvoked_keyguardNotified() {
+        featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        val callback = getBackInvokedCallback()
+        whenever(statusBarKeyguardViewManager.canHandleBackPressed()).thenReturn(true)
+
+        callback.onBackInvoked()
+
+        verify(statusBarKeyguardViewManager).onBackPressed()
+    }
+
+    @Test
+    fun animationFlagOn_callbackIsAnimationCallback() {
+        featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+
+        val callback = getBackInvokedCallback()
+
+        assertThat(callback).isInstanceOf(OnBackAnimationCallback::class.java)
+    }
+
+    @Test
+    fun onBackProgressed_shadeCannotBeCollapsed_shadeViewControllerNotNotified() {
+        featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        val callback = getBackInvokedCallback() as OnBackAnimationCallback
+
+        whenever(shadeViewController.canBeCollapsed()).thenReturn(false)
+
+        callback.onBackProgressed(createBackEvent(0.3f))
+
+        verify(shadeViewController, never()).onBackProgressed(0.3f)
+    }
+
+    @Test
+    fun onBackProgressed_shadeCanBeCollapsed_shadeViewControllerNotified() {
+        featureFlags.set(Flags.WM_SHADE_ANIMATE_BACK_GESTURE, true)
+        backActionInteractor.start()
+        windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        val callback = getBackInvokedCallback() as OnBackAnimationCallback
+
+        whenever(shadeViewController.canBeCollapsed()).thenReturn(true)
+
+        callback.onBackProgressed(createBackEvent(0.4f))
+
+        verify(shadeViewController).onBackProgressed(0.4f)
+    }
+
+    private fun getBackInvokedCallback(): OnBackInvokedCallback {
+        testScope.runCurrent()
+        val captor = argumentCaptor<OnBackInvokedCallback>()
+        verify(onBackInvokedDispatcher).registerOnBackInvokedCallback(any(), captor.capture())
+        return captor.value!!
+    }
+
+    private fun createBackEvent(progress: Float): BackEvent =
+        BackEvent(/* touchX= */ 0f, /* touchY= */ 0f, progress, /* swipeEdge= */ EDGE_LEFT)
+
+    private fun setWakefulness(state: WakefulnessState) {
+        val model = WakefulnessModel(state, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
+        keyguardRepository.setWakefulnessModel(model)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 7ab8e8b..e01b5af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -106,7 +106,6 @@
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.concurrency.Execution;
 import com.android.systemui.util.concurrency.FakeExecution;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.SecureSettings;
@@ -252,7 +251,9 @@
 
     @Before
     public void setUp() {
-        Execution execution = new FakeExecution();
+        mContext.getOrCreateTestableResources()
+                .addOverride(com.android.internal.R.bool.config_ignoreUdfpsVote, false);
+
         mUdfpsUtils = new UdfpsUtils();
 
         when(mLayoutInflater.inflate(R.layout.udfps_view, null, false))
@@ -1616,4 +1617,43 @@
         // THEN vibrate is used
         verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
     }
+
+    @Test
+    public void aodInterrupt_withNewTouchDetection() throws RemoteException {
+        mUdfpsController.cancelAodSendFingerUpAction();
+        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+                0L);
+        final TouchProcessorResult processorResultDown =
+                new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
+                        1 /* pointerId */, touchData);
+
+        // Enable new touch detection.
+        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
+
+        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
+        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
+
+        // GIVEN that the overlay is showing and screen is on and fp is running
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, 0,
+                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mScreenObserver.onScreenTurnedOn();
+        mFgExecutor.runAllReady();
+
+        // WHEN fingerprint is requested because of AOD interrupt
+        mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
+
+        // Check case where touch driver sends touch to UdfpsView as well
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                processorResultDown);
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+
+        mBiometricExecutor.runAllReady();
+
+        // THEN only one onPointerDown is sent
+        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 47084c0..0ed46da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -20,6 +20,7 @@
 import android.hardware.face.FaceSensorPropertiesInternal
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import android.view.HapticFeedbackConstants
+import android.view.MotionEvent
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
@@ -500,6 +501,81 @@
     }
 
     @Test
+    fun auto_confirm_authentication_when_finger_down() = runGenericTest {
+        val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
+
+        // No icon button when face only, can't confirm before auth
+        if (!testCase.isFaceOnly) {
+            viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_DOWN))
+        }
+        viewModel.showAuthenticated(testCase.authenticatedModality, 0)
+
+        val authenticating by collectLastValue(viewModel.isAuthenticating)
+        val authenticated by collectLastValue(viewModel.isAuthenticated)
+        val message by collectLastValue(viewModel.message)
+        val size by collectLastValue(viewModel.size)
+        val legacyState by collectLastValue(viewModel.legacyState)
+        val canTryAgain by collectLastValue(viewModel.canTryAgainNow)
+
+        assertThat(authenticating).isFalse()
+        assertThat(canTryAgain).isFalse()
+        assertThat(authenticated?.isAuthenticated).isTrue()
+
+        if (testCase.isFaceOnly && expectConfirmation) {
+            assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_PENDING_CONFIRMATION)
+
+            assertThat(size).isEqualTo(PromptSize.MEDIUM)
+            assertButtonsVisible(
+                cancel = true,
+                confirm = true,
+            )
+
+            viewModel.confirmAuthenticated()
+            assertThat(message).isEqualTo(PromptMessage.Empty)
+            assertButtonsVisible()
+        } else {
+            assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+        }
+    }
+
+    @Test
+    fun cannot_auto_confirm_authentication_when_finger_up() = runGenericTest {
+        val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
+
+        // No icon button when face only, can't confirm before auth
+        if (!testCase.isFaceOnly) {
+            viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_DOWN))
+            viewModel.onOverlayTouch(obtainMotionEvent(MotionEvent.ACTION_UP))
+        }
+        viewModel.showAuthenticated(testCase.authenticatedModality, 0)
+
+        val authenticating by collectLastValue(viewModel.isAuthenticating)
+        val authenticated by collectLastValue(viewModel.isAuthenticated)
+        val message by collectLastValue(viewModel.message)
+        val size by collectLastValue(viewModel.size)
+        val legacyState by collectLastValue(viewModel.legacyState)
+        val canTryAgain by collectLastValue(viewModel.canTryAgainNow)
+
+        assertThat(authenticated?.needsUserConfirmation).isEqualTo(expectConfirmation)
+        if (expectConfirmation) {
+            assertThat(size).isEqualTo(PromptSize.MEDIUM)
+            assertButtonsVisible(
+                cancel = true,
+                confirm = true,
+            )
+
+            viewModel.confirmAuthenticated()
+            assertThat(message).isEqualTo(PromptMessage.Empty)
+            assertButtonsVisible()
+        }
+
+        assertThat(authenticating).isFalse()
+        assertThat(authenticated?.isAuthenticated).isTrue()
+        assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+        assertThat(canTryAgain).isFalse()
+    }
+
+    @Test
     fun cannot_confirm_unless_authenticated() = runGenericTest {
         val authenticating by collectLastValue(viewModel.isAuthenticating)
         val authenticated by collectLastValue(viewModel.isAuthenticated)
@@ -679,6 +755,10 @@
         testScope.runTest { block() }
     }
 
+    /** Obtain a MotionEvent with the specified MotionEvent action constant */
+    private fun obtainMotionEvent(action: Int): MotionEvent =
+        MotionEvent.obtain(0, 0, action, 0f, 0f, 0)
+
     companion object {
         @JvmStatic
         @Parameterized.Parameters(name = "{0}")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
index 937a7a9..037c1ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.KotlinArgumentCaptor
 import com.android.systemui.util.mockito.eq
@@ -55,6 +56,8 @@
     @Mock
     lateinit var centralSurfaces: CentralSurfaces
     @Mock
+    lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock
     lateinit var keyguardStateController: KeyguardStateController
     @Mock
     lateinit var packageManager: PackageManager
@@ -91,6 +94,7 @@
             context = mock(),
             centralSurfaces = centralSurfaces,
             keyguardStateController = keyguardStateController,
+            statusBarKeyguardViewManager = statusBarKeyguardViewManager,
             packageManager = packageManager,
             activityManager = activityManager,
             activityStarter = activityStarter,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
index 3df9cbb..7fa828f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryImplTest.kt
@@ -9,6 +9,7 @@
 import android.os.UserManager
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.coroutines.collectLastValue
@@ -39,6 +40,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
+@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 class CommunalWidgetRepositoryImplTest : SysuiTestCase() {
     @Mock private lateinit var appWidgetManager: AppWidgetManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
index e3a75f1..09cb929 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/ui/view/layout/blueprints/DefaultCommunalBlueprintTest.kt
@@ -1,9 +1,11 @@
 package com.android.systemui.communal.ui.view.layout.blueprints
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.ui.view.layout.sections.DefaultCommunalWidgetSection
 import org.junit.Before
@@ -13,7 +15,8 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class DefaultCommunalBlueprintTest : SysuiTestCase() {
@@ -28,9 +31,16 @@
     }
 
     @Test
-    fun apply() {
+    fun addView() {
+        val constraintLayout = ConstraintLayout(context, null)
+        blueprint.addViews(null, constraintLayout)
+        verify(widgetSection).addViews(constraintLayout)
+    }
+
+    @Test
+    fun applyConstraints() {
         val cs = ConstraintSet()
-        blueprint.apply(cs)
-        verify(widgetSection).apply(cs)
+        blueprint.applyConstraints(cs)
+        verify(widgetSection).applyConstraints(cs)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
index 0b27bc9..54f66dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
@@ -29,7 +29,6 @@
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import dagger.Lazy
 import java.util.Optional
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
@@ -173,10 +172,9 @@
     private fun setupComponent(enabled: Boolean): ControlsComponent {
         return ControlsComponent(
             enabled,
-            mContext,
-            Lazy { controller },
-            Lazy { uiController },
-            Lazy { listingController },
+            { controller },
+            { uiController },
+            { listingController },
             lockPatternUtils,
             keyguardStateController,
             userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index b1061ba..74d0d21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -36,7 +36,6 @@
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags.APP_PANELS_ALL_APPS_ALLOWED
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.ActivityTaskManagerProxy
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -123,9 +122,6 @@
                         arrayOf(componentName.packageName)
                 )
 
-        // Return false by default, we'll test the true path
-        `when`(featureFlags.isEnabled(APP_PANELS_ALL_APPS_ALLOWED)).thenReturn(false)
-
         val wrapper = object : ContextWrapper(mContext) {
             override fun createContextAsUser(user: UserHandle, flags: Int): Context {
                 return baseContext
@@ -469,38 +465,7 @@
     }
 
     @Test
-    fun testPackageNotPreferred_nullPanel() {
-        mContext.orCreateTestableResources
-                .addOverride(R.array.config_controlsPreferredPackages, arrayOf<String>())
-
-        val serviceInfo = ServiceInfo(
-                componentName,
-                activityName
-        )
-
-        `when`(packageManager.getComponentEnabledSetting(eq(activityName)))
-                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
-
-        setUpQueryResult(listOf(
-                ActivityInfo(
-                        activityName,
-                        exported = true,
-                        permission = Manifest.permission.BIND_CONTROLS
-                )
-        ))
-
-        val list = listOf(serviceInfo)
-        serviceListingCallbackCaptor.value.onServicesReloaded(list)
-
-        executor.runAllReady()
-
-        assertNull(controller.getCurrentServices()[0].panelActivity)
-    }
-
-    @Test
-    fun testPackageNotPreferred_allowAllApps_correctPanel() {
-        `when`(featureFlags.isEnabled(APP_PANELS_ALL_APPS_ALLOWED)).thenReturn(true)
-
+    fun testPackageNotPreferred_correctPanel() {
         mContext.orCreateTestableResources
                 .addOverride(R.array.config_controlsPreferredPackages, arrayOf<String>())
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
new file mode 100644
index 0000000..588e34d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TemperatureControlBehaviorTest.kt
@@ -0,0 +1,98 @@
+package com.android.systemui.controls.ui
+
+import android.app.PendingIntent
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.service.controls.Control
+import android.service.controls.DeviceTypes
+import android.service.controls.templates.TemperatureControlTemplate
+import android.service.controls.templates.ThumbnailTemplate
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.ControlsMetricsLogger
+import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class TemperatureControlBehaviorTest : SysuiTestCase() {
+
+    @Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger
+    @Mock lateinit var controlActionCoordinator: ControlActionCoordinator
+    @Mock lateinit var controlsController: ControlsController
+
+    private val fakeSystemClock = FakeSystemClock()
+    private val underTest = TemperatureControlBehavior()
+
+    private lateinit var viewHolder: ControlViewHolder
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        viewHolder =
+            ControlViewHolder(
+                LayoutInflater.from(mContext).inflate(R.layout.controls_base_item, null, false)
+                    as ViewGroup,
+                controlsController,
+                FakeExecutor(fakeSystemClock),
+                FakeExecutor(fakeSystemClock),
+                controlActionCoordinator,
+                controlsMetricsLogger,
+                0,
+                0,
+            )
+    }
+
+    @Test
+    fun testBehaviourSupportsThumbnailSubBehaviour() {
+        val controlWithState =
+            ControlWithState(
+                ComponentName("test.pkg", "TestClass"),
+                ControlInfo(
+                    "test_id",
+                    "test title",
+                    "test subtitle",
+                    DeviceTypes.TYPE_AC_UNIT,
+                ),
+                Control.StatefulBuilder(
+                        "",
+                        PendingIntent.getActivity(
+                            context,
+                            0,
+                            Intent(),
+                            PendingIntent.FLAG_IMMUTABLE,
+                        ),
+                    )
+                    .setControlTemplate(
+                        TemperatureControlTemplate(
+                            "test id",
+                            ThumbnailTemplate(
+                                "test id",
+                                false,
+                                Icon.createWithContentUri(""),
+                                "test description",
+                            ),
+                            0,
+                            0,
+                            0
+                        )
+                    )
+                    .setStatus(Control.STATUS_OK)
+                    .build()
+            )
+        viewHolder.bindData(controlWithState, false)
+        underTest.initialize(viewHolder)
+
+        underTest.bind(controlWithState, 0) // no crash
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index 9be54fb..4bd380e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -52,6 +52,7 @@
 
     private val displayManager = mock<DisplayManager>()
     private val displayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
+    private val connectedDisplayListener = kotlinArgumentCaptor<DisplayManager.DisplayListener>()
 
     private val testHandler = FakeHandler(Looper.getMainLooper())
     private val testScope = TestScope(UnconfinedTestDispatcher())
@@ -114,7 +115,7 @@
 
             // Let's make sure it has *NOT* been unregistered, as there is still a subscriber.
             setDisplays(1)
-            displayListener.value.onDisplayAdded(1)
+            sendOnDisplayAdded(1)
             assertThat(firstSubscriber?.ids()).containsExactly(1)
         }
 
@@ -127,7 +128,7 @@
             val value by latestDisplayFlowValue()
 
             setDisplays(1)
-            displayListener.value.onDisplayAdded(1)
+            sendOnDisplayAdded(1)
 
             assertThat(value?.ids()).containsExactly(1)
         }
@@ -138,13 +139,13 @@
             val value by latestDisplayFlowValue()
 
             setDisplays(1, 2, 3, 4)
-            displayListener.value.onDisplayAdded(1)
-            displayListener.value.onDisplayAdded(2)
-            displayListener.value.onDisplayAdded(3)
-            displayListener.value.onDisplayAdded(4)
+            sendOnDisplayAdded(1)
+            sendOnDisplayAdded(2)
+            sendOnDisplayAdded(3)
+            sendOnDisplayAdded(4)
 
             setDisplays(1, 2, 3)
-            displayListener.value.onDisplayRemoved(4)
+            sendOnDisplayRemoved(4)
 
             assertThat(value?.ids()).containsExactly(1, 2, 3)
         }
@@ -155,26 +156,248 @@
             val value by latestDisplayFlowValue()
 
             setDisplays(1, 2, 3, 4)
-            displayListener.value.onDisplayAdded(1)
-            displayListener.value.onDisplayAdded(2)
-            displayListener.value.onDisplayAdded(3)
-            displayListener.value.onDisplayAdded(4)
+            sendOnDisplayAdded(1)
+            sendOnDisplayAdded(2)
+            sendOnDisplayAdded(3)
+            sendOnDisplayAdded(4)
 
             displayListener.value.onDisplayChanged(4)
 
             assertThat(value?.ids()).containsExactly(1, 2, 3, 4)
         }
 
+    @Test
+    fun onDisplayConnected_pendingDisplayReceived() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+
+            assertThat(pendingDisplay!!.id).isEqualTo(1)
+        }
+
+    @Test
+    fun onDisplayDisconnected_pendingDisplayNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+            sendOnDisplayConnected(1)
+
+            assertThat(pendingDisplay).isNotNull()
+
+            sendOnDisplayDisconnected(1)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onDisplayDisconnected_unknownDisplay_doesNotSendNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+            sendOnDisplayConnected(1)
+
+            assertThat(pendingDisplay).isNotNull()
+
+            sendOnDisplayDisconnected(2)
+
+            assertThat(pendingDisplay).isNotNull()
+        }
+
+    @Test
+    fun onDisplayConnected_multipleTimes_sendsOnlyTheMaximum() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            sendOnDisplayConnected(2)
+
+            assertThat(pendingDisplay!!.id).isEqualTo(2)
+        }
+
+    @Test
+    fun onPendingDisplay_enable_displayEnabled() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.enable()
+
+            verify(displayManager).enableConnectedDisplay(eq(1))
+        }
+
+    @Test
+    fun onPendingDisplay_enableBySysui_disabledBySomeoneElse_pendingDisplayStillIgnored() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.enable()
+            // to mock the display being really enabled:
+            sendOnDisplayAdded(1)
+
+            // Simulate the display being disabled by someone else. Now, sysui will have it in the
+            // "pending displays" list again, but it should be ignored.
+            sendOnDisplayRemoved(1)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onPendingDisplay_ignoredBySysui_enabledDisabledBySomeoneElse_pendingDisplayStillIgnored() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.ignore()
+
+            // to mock the display being enabled and disabled by someone else:
+            sendOnDisplayAdded(1)
+            sendOnDisplayRemoved(1)
+
+            // Sysui already decided to ignore it, so the pending display should be null.
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onPendingDisplay_disable_displayDisabled() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            pendingDisplay!!.disable()
+
+            verify(displayManager).disableConnectedDisplay(eq(1))
+        }
+
+    @Test
+    fun onPendingDisplay_ignore_pendingDisplayNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+            sendOnDisplayConnected(1)
+
+            pendingDisplay!!.ignore()
+
+            assertThat(pendingDisplay).isNull()
+            verify(displayManager, never()).disableConnectedDisplay(eq(1))
+            verify(displayManager, never()).enableConnectedDisplay(eq(1))
+        }
+
+    @Test
+    fun onPendingDisplay_enabled_pendingDisplayNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            assertThat(pendingDisplay).isNotNull()
+
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun onPendingDisplay_multipleConnected_oneEnabled_pendingDisplayNotNull() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            sendOnDisplayConnected(1)
+            sendOnDisplayConnected(2)
+
+            assertThat(pendingDisplay).isNotNull()
+
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+
+            assertThat(pendingDisplay).isNotNull()
+            assertThat(pendingDisplay!!.id).isEqualTo(2)
+
+            setDisplays(1, 2)
+            sendOnDisplayAdded(2)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
+    @Test
+    fun pendingDisplay_connectedDisconnectedAndReconnected_expectedPendingDisplayState() =
+        testScope.runTest {
+            val pendingDisplay by lastPendingDisplay()
+
+            // Plug the cable
+            sendOnDisplayConnected(1)
+
+            // Enable it
+            assertThat(pendingDisplay).isNotNull()
+            pendingDisplay!!.enable()
+
+            // Enabled
+            verify(displayManager).enableConnectedDisplay(1)
+            setDisplays(1)
+            sendOnDisplayAdded(1)
+
+            // No more pending displays
+            assertThat(pendingDisplay).isNull()
+
+            // Let's disconnect the cable
+            setDisplays()
+            sendOnDisplayRemoved(1)
+            sendOnDisplayDisconnected(1)
+
+            assertThat(pendingDisplay).isNull()
+
+            // Let's reconnect it
+            sendOnDisplayConnected(1)
+
+            assertThat(pendingDisplay).isNotNull()
+        }
+
     private fun Iterable<Display>.ids(): List<Int> = map { it.displayId }
 
     // Wrapper to capture the displayListener.
     private fun TestScope.latestDisplayFlowValue(): FlowValue<Set<Display>?> {
         val flowValue = collectLastValue(displayRepository.displays)
-        verify(displayManager)
-            .registerDisplayListener(displayListener.capture(), eq(testHandler), anyLong())
+        captureAddedRemovedListener()
         return flowValue
     }
 
+    private fun TestScope.lastPendingDisplay(): FlowValue<DisplayRepository.PendingDisplay?> {
+        val flowValue = collectLastValue(displayRepository.pendingDisplay)
+        captureAddedRemovedListener()
+        verify(displayManager)
+            .registerDisplayListener(
+                connectedDisplayListener.capture(),
+                eq(testHandler),
+                eq(DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED)
+            )
+        return flowValue
+    }
+
+    private fun captureAddedRemovedListener() {
+        verify(displayManager)
+            .registerDisplayListener(
+                displayListener.capture(),
+                eq(testHandler),
+                eq(
+                    DisplayManager.EVENT_FLAG_DISPLAY_ADDED or
+                        DisplayManager.EVENT_FLAG_DISPLAY_CHANGED or
+                        DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
+                )
+            )
+    }
+    private fun sendOnDisplayAdded(id: Int) {
+        displayListener.value.onDisplayAdded(id)
+    }
+    private fun sendOnDisplayRemoved(id: Int) {
+        displayListener.value.onDisplayRemoved(id)
+    }
+
+    private fun sendOnDisplayDisconnected(id: Int) {
+        connectedDisplayListener.value.onDisplayDisconnected(id)
+    }
+
+    private fun sendOnDisplayConnected(id: Int) {
+        connectedDisplayListener.value.onDisplayConnected(id)
+    }
+
     private fun setDisplays(displays: List<Display>) {
         whenever(displayManager.displays).thenReturn(displays.toTypedArray())
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
index eb0ad69..26ee094 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/domain/interactor/ConnectedDisplayInteractorTest.kt
@@ -26,13 +26,17 @@
 import com.android.systemui.coroutines.FlowValue
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.display.data.repository.createPendingDisplay
 import com.android.systemui.display.data.repository.display
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -43,10 +47,16 @@
 class ConnectedDisplayInteractorTest : SysuiTestCase() {
 
     private val fakeDisplayRepository = FakeDisplayRepository()
+    private val fakeKeyguardRepository = FakeKeyguardRepository()
     private val connectedDisplayStateProvider: ConnectedDisplayInteractor =
-        ConnectedDisplayInteractorImpl(fakeDisplayRepository)
+        ConnectedDisplayInteractorImpl(fakeKeyguardRepository, fakeDisplayRepository)
     private val testScope = TestScope(UnconfinedTestDispatcher())
 
+    @Before
+    fun setup() {
+        fakeKeyguardRepository.setKeyguardShowing(false)
+    }
+
     @Test
     fun displayState_nullDisplays_disconnected() =
         testScope.runTest {
@@ -126,6 +136,48 @@
             assertThat(value).isEqualTo(State.CONNECTED_SECURE)
         }
 
+    @Test
+    fun pendingDisplay_propagated() =
+        testScope.runTest {
+            val value by lastPendingDisplay()
+            val pendingDisplayId = createPendingDisplay()
+
+            fakeDisplayRepository.emit(pendingDisplayId)
+
+            assertThat(value).isNotNull()
+        }
+
+    @Test
+    fun onPendingDisplay_keyguardShowing_returnsPendingDisplay() =
+        testScope.runTest {
+            fakeKeyguardRepository.setKeyguardShowing(true)
+            val pendingDisplay by lastPendingDisplay()
+
+            fakeDisplayRepository.emit(createPendingDisplay())
+            assertThat(pendingDisplay).isNull()
+
+            fakeKeyguardRepository.setKeyguardShowing(false)
+
+            assertThat(pendingDisplay).isNotNull()
+        }
+
+    @Test
+    fun onPendingDisplay_keyguardShowing_returnsNull() =
+        testScope.runTest {
+            fakeKeyguardRepository.setKeyguardShowing(false)
+            val pendingDisplay by lastPendingDisplay()
+
+            fakeDisplayRepository.emit(createPendingDisplay())
+            assertThat(pendingDisplay).isNotNull()
+
+            fakeKeyguardRepository.setKeyguardShowing(true)
+
+            assertThat(pendingDisplay).isNull()
+        }
+
     private fun TestScope.lastValue(): FlowValue<State?> =
         collectLastValue(connectedDisplayStateProvider.connectedDisplayState)
+
+    private fun TestScope.lastPendingDisplay(): FlowValue<PendingDisplay?> =
+        collectLastValue(connectedDisplayStateProvider.pendingDisplay)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
new file mode 100644
index 0000000..46f7582
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/display/ui/view/MirroringConfirmationDialogTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.ui.view
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class MirroringConfirmationDialogTest : SysuiTestCase() {
+
+    private lateinit var dialog: MirroringConfirmationDialog
+
+    private val onStartMirroringCallback = mock<View.OnClickListener>()
+    private val onCancelCallback = mock<View.OnClickListener>()
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        dialog = MirroringConfirmationDialog(context, onStartMirroringCallback, onCancelCallback)
+    }
+
+    @Test
+    fun startMirroringButton_clicked_callsCorrectCallback() {
+        dialog.show()
+
+        dialog.requireViewById<View>(R.id.enable_display).callOnClick()
+
+        verify(onStartMirroringCallback).onClick(any())
+        verify(onCancelCallback, never()).onClick(any())
+    }
+
+    @Test
+    fun cancelButton_clicked_callsCorrectCallback() {
+        dialog.show()
+
+        dialog.requireViewById<View>(R.id.cancel).callOnClick()
+
+        verify(onCancelCallback).onClick(any())
+        verify(onStartMirroringCallback, never()).onClick(any())
+    }
+
+    @Test
+    fun onCancel_afterEnablingMirroring_cancelCallbackNotCalled() {
+        dialog.show()
+        dialog.requireViewById<View>(R.id.enable_display).callOnClick()
+
+        dialog.cancel()
+
+        verify(onCancelCallback, never()).onClick(any())
+        verify(onStartMirroringCallback).onClick(any())
+    }
+
+    @Test
+    fun onDismiss_afterEnablingMirroring_cancelCallbackNotCalled() {
+        dialog.show()
+        dialog.requireViewById<View>(R.id.enable_display).callOnClick()
+
+        dialog.dismiss()
+
+        verify(onCancelCallback, never()).onClick(any())
+        verify(onStartMirroringCallback).onClick(any())
+    }
+
+    @After
+    fun teardown() {
+        if (::dialog.isInitialized) {
+            dialog.dismiss()
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index 57307fc..781ad6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -3,9 +3,10 @@
 import android.animation.Animator
 import android.animation.AnimatorSet
 import android.animation.ValueAnimator
-import android.testing.AndroidTestingRunner
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.complication.ComplicationHostViewController
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
@@ -29,8 +30,9 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class DreamOverlayAnimationsControllerTest : SysuiTestCase() {
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
index 9f534ef..21192fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
@@ -15,8 +15,9 @@
  */
 package com.android.systemui.dreams
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -29,8 +30,9 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class DreamOverlayCallbackControllerTest : SysuiTestCase() {
 
     @Mock private lateinit var callback: DreamOverlayCallbackController.Callback
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 8786520..7c36642 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -28,21 +28,22 @@
 import android.content.res.Resources;
 import android.graphics.Region;
 import android.os.Handler;
-import android.testing.AndroidTestingRunner;
 import android.view.AttachedSurfaceControl;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.complication.ComplicationHostViewController;
-import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.complication.ComplicationHostViewController;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
 import com.android.systemui.statusbar.BlurUtils;
 
 import org.junit.Before;
@@ -52,8 +53,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
     private static final int MAX_BURN_IN_OFFSET = 20;
     private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
index 25d4c47..be7638e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayNotificationCountProviderTest.java
@@ -22,10 +22,11 @@
 
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
@@ -37,8 +38,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamOverlayNotificationCountProviderTest extends SysuiTestCase {
     @Mock
     NotificationListener mNotificationListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index d99f0da..8379f73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -37,7 +37,6 @@
 import android.service.dreams.IDreamOverlayCallback;
 import android.service.dreams.IDreamOverlayClient;
 import android.service.dreams.IDreamOverlayClientCallback;
-import android.testing.AndroidTestingRunner;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -45,10 +44,12 @@
 
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.ComplicationLayoutEngine;
 import com.android.systemui.dreams.complication.HideComplicationTouchHandler;
@@ -71,8 +72,9 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamOverlayServiceTest extends SysuiTestCase {
     private static final ComponentName LOW_LIGHT_COMPONENT = new ComponentName("package",
             "lowlight");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 44a78ac..2ef227c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -26,10 +26,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.Complication;
 import com.android.systemui.flags.FeatureFlags;
@@ -48,8 +48,9 @@
 
 import java.util.Collection;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamOverlayStateControllerTest extends SysuiTestCase {
     @Mock
     DreamOverlayStateController.Callback mCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
index a78886f..12cb332 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarItemsProviderTest.java
@@ -21,10 +21,10 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -36,8 +36,9 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamOverlayStatusBarItemsProviderTest extends SysuiTestCase {
     @Mock
     DreamOverlayStatusBarItemsProvider.Callback mCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 4e74f451..af2dab5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -41,12 +41,13 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.R;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.core.FakeLogBuffer;
@@ -71,8 +72,9 @@
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamOverlayStatusBarViewControllerTest extends SysuiTestCase {
     private static final String NOTIFICATION_INDICATOR_FORMATTER_STRING =
             "{count, plural, =1 {# notification} other {# notifications}}";
@@ -92,8 +94,6 @@
     @Mock
     AlarmManager mAlarmManager;
     @Mock
-    AlarmManager.AlarmClockInfo mAlarmClockInfo;
-    @Mock
     NextAlarmController mNextAlarmController;
     @Mock
     DateFormatUtil mDateFormatUtil;
@@ -203,8 +203,9 @@
 
     @Test
     public void testOnViewAttachedShowsAlarmIconWhenAlarmExists() {
-        when(mAlarmClockInfo.getTriggerTime()).thenReturn(1L);
-        when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(mAlarmClockInfo);
+        final AlarmManager.AlarmClockInfo alarmClockInfo =
+                new AlarmManager.AlarmClockInfo(1L, null);
+        when(mAlarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmClockInfo);
         mController.onViewAttached();
         verify(mView).showIcon(
                 eq(DreamOverlayStatusBarView.STATUS_ICON_ALARM_SET), eq(true), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
index eed4dbc..d32788d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/HideComplicationTouchHandlerTest.java
@@ -23,13 +23,14 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Handler;
-import android.testing.AndroidTestingRunner;
 import android.view.MotionEvent;
 import android.view.View;
 
 import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.complication.Complication;
 import com.android.systemui.dreams.DreamOverlayStateController;
@@ -48,8 +49,9 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class HideComplicationTouchHandlerTest extends SysuiTestCase {
     private static final int RESTORE_TIMEOUT = 1000;
     private static final int HIDE_DELAY = 500;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
index 6a17889..4a7700f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/AssistantAttentionConditionTest.java
@@ -23,10 +23,10 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.assist.AssistManager.VisualQueryAttentionListener;
@@ -41,8 +41,9 @@
 
 import kotlinx.coroutines.CoroutineScope;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class AssistantAttentionConditionTest extends SysuiTestCase {
     @Mock
     Condition.Callback mCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
index 68c7965..cd2efde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -25,12 +25,13 @@
 import static org.mockito.Mockito.when;
 
 import android.app.DreamManager;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shared.condition.Condition;
 
@@ -43,8 +44,9 @@
 
 import kotlinx.coroutines.CoroutineScope;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class DreamConditionTest extends SysuiTestCase {
     @Mock
     Condition.Callback mCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 3f9b198..90076fd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -31,16 +31,17 @@
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.testing.AndroidTestingRunner;
 import android.view.GestureDetector;
 import android.view.GestureDetector.OnGestureListener;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
 import com.android.systemui.dreams.touch.scrim.ScrimController;
@@ -56,6 +57,7 @@
 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;
 import org.mockito.MockitoAnnotations;
@@ -63,8 +65,9 @@
 import java.util.Collections;
 import java.util.Optional;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
     @Mock
     CentralSurfaces mCentralSurfaces;
@@ -107,6 +110,12 @@
     @Mock
     LockPatternUtils mLockPatternUtils;
 
+    @Mock
+    Region mRegion;
+
+    @Captor
+    ArgumentCaptor<Rect> mRectCaptor;
+
     FakeUserTracker mUserTracker;
 
     private static final float TOUCH_REGION = .3f;
@@ -153,10 +162,10 @@
      */
     @Test
     public void testSessionStart() {
-        final Region region = Region.obtain();
-        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, region);
+        mTouchHandler.getTouchInitiationRegion(SCREEN_BOUNDS, mRegion);
 
-        final Rect bounds = region.getBounds();
+        verify(mRegion).op(mRectCaptor.capture(), eq(Region.Op.UNION));
+        final Rect bounds = mRectCaptor.getValue();
 
         final Rect expected = new Rect();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
index 2b98214..ff6d97d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/ShadeTouchHandlerTest.java
@@ -21,12 +21,13 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.shared.system.InputChannelCompat;
@@ -42,8 +43,9 @@
 
 import java.util.Optional;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class ShadeTouchHandlerTest extends SysuiTestCase {
     @Mock
     CentralSurfaces mCentralSurfaces;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
index 79c535a..da39381 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -22,10 +22,11 @@
 import static org.mockito.Mockito.verify;
 
 import android.os.PowerManager;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.shade.ShadeExpansionChangeEvent;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -37,8 +38,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class BouncerlessScrimControllerTest extends SysuiTestCase {
     @Mock
     BouncerlessScrimController.Callback mCallback;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
index ac9822d..81f6fe3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
@@ -22,10 +22,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
-
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.RoboPilotTest;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -38,8 +38,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@RoboPilotTest
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class ScrimManagerTest extends SysuiTestCase {
     @Mock
     ScrimController mBouncerlessScrimController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderTest.kt
index ccd631e..8f66344 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/graphics/ImageLoaderTest.kt
@@ -9,6 +9,7 @@
 import android.graphics.drawable.Icon
 import android.graphics.drawable.VectorDrawable
 import android.net.Uri
+import android.util.Size
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
@@ -78,12 +79,19 @@
         }
 
     @Test
-    fun invalidIcon_returnsNull() =
+    fun invalidIcon_loadDrawable_returnsNull() =
         testScope.runTest {
             assertThat(imageLoader.loadDrawable(Icon.createWithFilePath("this is broken"))).isNull()
         }
 
     @Test
+    fun invalidIcon_loadSize_returnsNull() =
+        testScope.runTest {
+            assertThat(imageLoader.loadSize(Icon.createWithFilePath("this is broken"), context))
+                .isNull()
+        }
+
+    @Test
     fun invalidIS_returnsNull() =
         testScope.runTest {
             assertThat(
@@ -172,6 +180,17 @@
         }
 
     @Test
+    fun validBitmapIcon_loadSize_returnsNull() =
+        testScope.runTest {
+            val bitmap =
+                BitmapFactory.decodeResource(
+                    context.resources,
+                    R.drawable.dessert_zombiegingerbread
+                )
+            assertThat(imageLoader.loadSize(Icon.createWithBitmap(bitmap), context)).isNull()
+        }
+
+    @Test
     fun validUriIcon_returnsBitmapDrawable() =
         testScope.runTest {
             val bitmap =
@@ -186,6 +205,17 @@
         }
 
     @Test
+    fun validUriIcon_returnsSize() =
+        testScope.runTest {
+            val drawable = context.resources.getDrawable(R.drawable.dessert_zombiegingerbread)
+            val uri =
+                "android.resource://${context.packageName}/${R.drawable.dessert_zombiegingerbread}"
+            val loadedSize =
+                imageLoader.loadSize(Icon.createWithContentUri(Uri.parse(uri)), context)
+            assertSizeEqualToDrawableSize(loadedSize, drawable)
+        }
+
+    @Test
     fun validDataIcon_returnsBitmapDrawable() =
         testScope.runTest {
             val bitmap =
@@ -205,6 +235,54 @@
         }
 
     @Test
+    fun validDataIcon_loadSize_returnsNull() =
+        testScope.runTest {
+            val bitmap =
+                BitmapFactory.decodeResource(
+                    context.resources,
+                    R.drawable.dessert_zombiegingerbread
+                )
+            val bos =
+                ByteArrayOutputStream(
+                    bitmap.byteCount * 2
+                ) // Compressed bitmap should be smaller than its source.
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos)
+
+            val array = bos.toByteArray()
+            assertThat(imageLoader.loadSize(Icon.createWithData(array, 0, array.size), context))
+                .isNull()
+        }
+
+    @Test
+    fun validResourceIcon_returnsBitmapDrawable() =
+        testScope.runTest {
+            val bitmap = context.resources.getDrawable(R.drawable.dessert_zombiegingerbread)
+            val loadedDrawable =
+                imageLoader.loadDrawable(
+                    Icon.createWithResource(
+                        "com.android.systemui.tests",
+                        R.drawable.dessert_zombiegingerbread
+                    )
+                )
+            assertBitmapEqualToDrawable(loadedDrawable, (bitmap as BitmapDrawable).bitmap)
+        }
+
+    @Test
+    fun validResourceIcon_loadSize_returnsNull() =
+        testScope.runTest {
+            assertThat(
+                    imageLoader.loadSize(
+                        Icon.createWithResource(
+                            "com.android.systemui.tests",
+                            R.drawable.dessert_zombiegingerbread
+                        ),
+                        context
+                    )
+                )
+                .isNull()
+        }
+
+    @Test
     fun validSystemResourceIcon_returnsBitmapDrawable() =
         testScope.runTest {
             val bitmap =
@@ -217,6 +295,18 @@
         }
 
     @Test
+    fun validSystemResourceIcon_loadSize_returnsNull() =
+        testScope.runTest {
+            assertThat(
+                    imageLoader.loadSize(
+                        Icon.createWithResource("android", android.R.drawable.ic_dialog_alert),
+                        context
+                    )
+                )
+                .isNull()
+        }
+
+    @Test
     fun invalidDifferentPackageResourceIcon_returnsNull() =
         testScope.runTest {
             val loadedDrawable =
@@ -230,6 +320,20 @@
         }
 
     @Test
+    fun invalidDifferentPackageResourceIcon_loadSize_returnsNull() =
+        testScope.runTest {
+            assertThat(
+                    imageLoader.loadDrawable(
+                        Icon.createWithResource(
+                            "noooope.wrong.package",
+                            R.drawable.dessert_zombiegingerbread
+                        )
+                    )
+                )
+                .isNull()
+        }
+
+    @Test
     fun validBitmapResource_widthMoreRestricted_downsizesKeepingAspectRatio() =
         testScope.runTest {
             val loadedDrawable =
@@ -343,4 +447,10 @@
         assertThat(actual?.width).isEqualTo(expected.width)
         assertThat(actual?.height).isEqualTo(expected.height)
     }
+
+    private fun assertSizeEqualToDrawableSize(actual: Size?, expected: Drawable) {
+        assertThat(actual).isNotNull()
+        assertThat(actual?.width).isEqualTo(expected.intrinsicWidth)
+        assertThat(actual?.height).isEqualTo(expected.intrinsicHeight)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SeekableSliderEventProducerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SeekableSliderEventProducerTest.kt
new file mode 100644
index 0000000..71a56cd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/haptics/slider/SeekableSliderEventProducerTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.haptics.slider
+
+import android.widget.SeekBar
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import junit.framework.Assert.assertEquals
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SeekableSliderEventProducerTest : SysuiTestCase() {
+
+    private val seekBar = SeekBar(mContext)
+    private val eventProducer = SeekableSliderEventProducer()
+    private val eventFlow = eventProducer.produceEvents()
+
+    @Test
+    fun onStartTrackingTouch_noProgress_trackingTouchEventProduced() = runTest {
+        val latest by collectLastValue(eventFlow)
+
+        eventProducer.onStartTrackingTouch(seekBar)
+
+        assertEquals(SliderEvent(SliderEventType.STARTED_TRACKING_TOUCH, 0F), latest)
+    }
+
+    @Test
+    fun onStopTrackingTouch_noProgress_StoppedTrackingTouchEventProduced() = runTest {
+        val latest by collectLastValue(eventFlow)
+
+        eventProducer.onStopTrackingTouch(seekBar)
+
+        assertEquals(SliderEvent(SliderEventType.STOPPED_TRACKING_TOUCH, 0F), latest)
+    }
+
+    @Test
+    fun onProgressChangeByUser_changeByUserEventProduced_withNormalizedProgress() = runTest {
+        val progress = 50
+        val latest by collectLastValue(eventFlow)
+
+        eventProducer.onProgressChanged(seekBar, progress, true)
+
+        assertEquals(SliderEvent(SliderEventType.PROGRESS_CHANGE_BY_USER, 0.5F), latest)
+    }
+
+    @Test
+    fun onProgressChangeByUser_zeroWidthSlider_changeByUserEventProduced_withMaxProgress() =
+        runTest {
+            // No-width slider where the min and max values are the same
+            seekBar.min = 100
+            seekBar.max = 100
+            val progress = 50
+            val latest by collectLastValue(eventFlow)
+
+            eventProducer.onProgressChanged(seekBar, progress, true)
+
+            assertEquals(SliderEvent(SliderEventType.PROGRESS_CHANGE_BY_USER, 1.0F), latest)
+        }
+
+    @Test
+    fun onProgressChangeByProgram_changeByProgramEventProduced_withNormalizedProgress() = runTest {
+        val progress = 50
+        val latest by collectLastValue(eventFlow)
+
+        eventProducer.onProgressChanged(seekBar, progress, false)
+
+        assertEquals(SliderEvent(SliderEventType.PROGRESS_CHANGE_BY_PROGRAM, 0.5F), latest)
+    }
+
+    @Test
+    fun onProgressChangeByProgram_zeroWidthSlider_changeByProgramEventProduced_withMaxProgress() =
+        runTest {
+            // No-width slider where the min and max values are the same
+            seekBar.min = 100
+            seekBar.max = 100
+            val progress = 50
+            val latest by collectLastValue(eventFlow)
+
+            eventProducer.onProgressChanged(seekBar, progress, false)
+
+            assertEquals(SliderEvent(SliderEventType.PROGRESS_CHANGE_BY_PROGRAM, 1.0F), latest)
+        }
+
+    @Test
+    fun onStartTrackingTouch_afterProgress_trackingTouchEventProduced_withNormalizedProgress() =
+        runTest {
+            val progress = 50
+            val latest by collectLastValue(eventFlow)
+
+            eventProducer.onProgressChanged(seekBar, progress, true)
+            eventProducer.onStartTrackingTouch(seekBar)
+
+            assertEquals(SliderEvent(SliderEventType.STARTED_TRACKING_TOUCH, 0.5F), latest)
+        }
+
+    @Test
+    fun onStopTrackingTouch_afterProgress_stopTrackingTouchEventProduced_withNormalizedProgress() =
+        runTest {
+            val progress = 50
+            val latest by collectLastValue(eventFlow)
+
+            eventProducer.onProgressChanged(seekBar, progress, true)
+            eventProducer.onStopTrackingTouch(seekBar)
+
+            assertEquals(SliderEvent(SliderEventType.STOPPED_TRACKING_TOUCH, 0.5F), latest)
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
index 36822e6..f62137c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -63,6 +63,7 @@
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
@@ -180,6 +181,10 @@
                 keyguardInteractor =
                     KeyguardInteractorFactory.create(
                             featureFlags = featureFlags,
+                            sceneInteractor =
+                                mock {
+                                    whenever(transitioningTo).thenReturn(MutableStateFlow(null))
+                                },
                         )
                         .keyguardInteractor,
                 lockPatternUtils = lockPatternUtils,
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 daafba2..f78d051 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -221,6 +221,7 @@
         mSystemClock = new FakeSystemClock();
         when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager);
         when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
+        when(mPowerManager.isInteractive()).thenReturn(true);
         when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
         when(mInteractionJankMonitor.end(anyInt())).thenReturn(true);
         mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
@@ -241,6 +242,7 @@
                 mConfigurationController,
                 mViewMediator,
                 mKeyguardBypassController,
+                mUiBgExecutor,
                 mColorExtractor,
                 mDumpManager,
                 mKeyguardStateController,
@@ -868,8 +870,6 @@
         when(mKeyguardStateController.isShowing()).thenReturn(true);
         TestableLooper.get(this).processAllMessages();
 
-        when(mPowerManager.isInteractive()).thenReturn(true);
-
         mViewMediator.onSystemReady();
         TestableLooper.get(this).processAllMessages();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 5ead16b..2691860 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.mockito.withArgCaptor
@@ -322,20 +323,20 @@
 
             val captor = argumentCaptor<StatusBarStateController.StateListener>()
             runCurrent()
-            verify(statusBarStateController).addCallback(captor.capture())
+            verify(statusBarStateController, atLeastOnce()).addCallback(captor.capture())
 
-            captor.value.onDozeAmountChanged(0.433f, 0.4f)
+            captor.allValues.forEach { it.onDozeAmountChanged(0.433f, 0.4f) }
             runCurrent()
-            captor.value.onDozeAmountChanged(0.498f, 0.5f)
+            captor.allValues.forEach { it.onDozeAmountChanged(0.498f, 0.5f) }
             runCurrent()
-            captor.value.onDozeAmountChanged(0.661f, 0.65f)
+            captor.allValues.forEach { it.onDozeAmountChanged(0.661f, 0.65f) }
             runCurrent()
 
             assertThat(values).isEqualTo(listOf(0f, 0.433f, 0.498f, 0.661f))
 
             job.cancel()
             runCurrent()
-            verify(statusBarStateController).removeCallback(captor.value)
+            verify(statusBarStateController).removeCallback(any())
         }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 972af4a..14cdf2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -15,6 +15,8 @@
  *
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.keyguard.domain.interactor
 
 import android.app.StatusBarManager
@@ -30,8 +32,15 @@
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.onCompletion
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -54,25 +63,33 @@
     private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
     private lateinit var configurationRepository: FakeConfigurationRepository
     private lateinit var shadeRepository: FakeShadeRepository
+    private lateinit var sceneInteractor: SceneInteractor
+    private lateinit var transitionState: MutableStateFlow<ObservableTransitionState>
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         featureFlags = FakeFeatureFlags().apply { set(FACE_AUTH_REFACTOR, true) }
         commandQueue = FakeCommandQueue()
-        testScope = TestScope()
-        repository = FakeKeyguardRepository()
+        val sceneTestUtils = SceneTestUtils(this)
+        testScope = sceneTestUtils.testScope
+        repository = sceneTestUtils.keyguardRepository
         bouncerRepository = FakeKeyguardBouncerRepository()
         configurationRepository = FakeConfigurationRepository()
         shadeRepository = FakeShadeRepository()
+        sceneInteractor = sceneTestUtils.sceneInteractor()
+        transitionState = MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Gone))
+        sceneInteractor.setTransitionState(transitionState)
         underTest =
             KeyguardInteractor(
-                repository,
-                commandQueue,
-                featureFlags,
-                bouncerRepository,
-                configurationRepository,
-                shadeRepository,
+                repository = repository,
+                commandQueue = commandQueue,
+                featureFlags = featureFlags,
+                sceneContainerFlags = sceneTestUtils.sceneContainerFlags,
+                bouncerRepository = bouncerRepository,
+                configurationRepository = configurationRepository,
+                shadeRepository = shadeRepository,
+                sceneInteractorProvider = { sceneInteractor },
             )
     }
 
@@ -180,4 +197,28 @@
 
             assertThat(secureCameraActive()).isFalse()
         }
+
+    @Test
+    fun animationDozingTransitions() =
+        testScope.runTest {
+            val isAnimate by collectLastValue(underTest.animateDozingTransitions)
+
+            underTest.setAnimateDozingTransitions(true)
+            runCurrent()
+            assertThat(isAnimate).isTrue()
+
+            underTest.setAnimateDozingTransitions(false)
+            runCurrent()
+            assertThat(isAnimate).isFalse()
+
+            underTest.setAnimateDozingTransitions(true)
+            transitionState.value =
+                ObservableTransitionState.Transition(
+                    fromScene = SceneKey.Gone,
+                    toScene = SceneKey.Lockscreen,
+                    progress = flowOf(0f),
+                )
+            runCurrent()
+            assertThat(isAnimate).isFalse()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index ca93246..d457605 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -1049,7 +1049,6 @@
     @Test
     fun occludedToAlternateBouncer() =
         testScope.runTest {
-
             // GIVEN a prior transition has run to OCCLUDED
             runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
             keyguardRepository.setKeyguardOccluded(true)
@@ -1073,6 +1072,31 @@
         }
 
     @Test
+    fun occludedToPrimaryBouncer() =
+        testScope.runTest {
+            // GIVEN a prior transition has run to OCCLUDED
+            runTransition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
+            keyguardRepository.setKeyguardOccluded(true)
+            runCurrent()
+
+            // WHEN primary bouncer shows
+            bouncerRepository.setPrimaryShow(true) // beverlyt
+            runCurrent()
+
+            val info =
+                withArgCaptor<TransitionInfo> {
+                    verify(transitionRepository).startTransition(capture(), anyBoolean())
+                }
+            // THEN a transition to AlternateBouncer should occur
+            assertThat(info.ownerName).isEqualTo("FromOccludedTransitionInteractor")
+            assertThat(info.from).isEqualTo(KeyguardState.OCCLUDED)
+            assertThat(info.to).isEqualTo(KeyguardState.PRIMARY_BOUNCER)
+            assertThat(info.animator).isNotNull()
+
+            coroutineContext.cancelChildren()
+        }
+
+    @Test
     fun primaryBouncerToOccluded() =
         testScope.runTest {
             // GIVEN device not sleeping
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
index f24ea6c..bdcb9ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/OccludingAppDeviceEntryInteractorTest.kt
@@ -52,6 +52,7 @@
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
@@ -121,6 +122,8 @@
                         repository = keyguardRepository,
                         bouncerRepository = bouncerRepository,
                         configurationRepository = configurationRepository,
+                        sceneInteractor =
+                            mock { whenever(transitioningTo).thenReturn(MutableStateFlow(null)) },
                     )
                     .keyguardInteractor,
                 PrimaryBouncerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
index addb181..bf57ecb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/blueprints/DefaultKeyguardBlueprintTest.kt
@@ -19,21 +19,29 @@
 
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.KeyguardRootView
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultAmbientIndicationAreaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultLockIconSection
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultSettingsPopupMenuSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
 import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
 import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
+import com.android.systemui.util.mockito.whenever
 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.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
@@ -50,7 +58,9 @@
     private lateinit var defaultAmbientIndicationAreaSection: DefaultAmbientIndicationAreaSection
     @Mock private lateinit var defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection
     @Mock private lateinit var defaultStatusViewSection: DefaultStatusViewSection
+    @Mock private lateinit var defaultNSSLSection: DefaultNotificationStackScrollLayoutSection
     @Mock private lateinit var splitShadeGuidelines: SplitShadeGuidelines
+    private val featureFlags = FakeFeatureFlags()
 
     @Before
     fun setup() {
@@ -64,20 +74,56 @@
                 defaultAmbientIndicationAreaSection,
                 defaultSettingsPopupMenuSection,
                 defaultStatusViewSection,
+                defaultNSSLSection,
                 splitShadeGuidelines,
+                featureFlags,
             )
+        featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, false)
     }
 
     @Test
-    fun apply() {
+    fun addViews() {
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(null, constraintLayout)
+        underTest.sections.forEach { verify(it, never()).addViews(constraintLayout) }
+    }
+
+    @Test
+    fun addViews_lazyInflateFlagOn() {
+        featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, true)
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(null, constraintLayout)
+        underTest.sections.forEach { verify(it).addViews(constraintLayout) }
+    }
+
+    @Test
+    fun addViews_withPrevBlueprint() {
+        val prevBlueprint = mock(KeyguardBlueprint::class.java)
+        whenever(prevBlueprint.sections)
+            .thenReturn(underTest.sections.minus(defaultLockIconSection))
+        featureFlags.set(Flags.LAZY_INFLATE_KEYGUARD, true)
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(prevBlueprint, constraintLayout)
+        underTest.sections.minus(defaultLockIconSection).forEach {
+            verify(it, never()).addViews(constraintLayout)
+        }
+
+        verify(defaultLockIconSection).addViews(constraintLayout)
+    }
+
+    @Test
+    fun addViews_withNextBlueprint() {
+        val nextBlueprint = mock(KeyguardBlueprint::class.java)
+        whenever(nextBlueprint.sections).thenReturn(setOf())
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.removeViews(nextBlueprint, constraintLayout)
+        underTest.sections.forEach { verify(it).removeViews(constraintLayout) }
+    }
+
+    @Test
+    fun applyConstraints() {
         val cs = ConstraintSet()
-        underTest.apply(cs)
-        verify(defaultIndicationAreaSection).apply(cs)
-        verify(defaultLockIconSection).apply(cs)
-        verify(defaultShortcutsSection).apply(cs)
-        verify(defaultAmbientIndicationAreaSection).apply(cs)
-        verify(defaultSettingsPopupMenuSection).apply(cs)
-        verify(defaultStatusViewSection).apply(cs)
-        verify(splitShadeGuidelines).apply(cs)
+        underTest.applyConstraints(cs)
+        underTest.sections.forEach { verify(it).applyConstraints(cs) }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
index 3dcc03d..4e31af22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultIndicationAreaSectionTest.kt
@@ -18,24 +18,68 @@
 package com.android.systemui.keyguard.ui.view.layout.sections
 
 import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
+import com.android.systemui.statusbar.KeyguardIndicationController
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
 
 @RunWith(JUnit4::class)
 @SmallTest
 class DefaultIndicationAreaSectionTest : SysuiTestCase() {
-    private val underTest = DefaultIndicationAreaSection(context)
+    @Mock private lateinit var keyguardIndicationAreaViewModel: KeyguardIndicationAreaViewModel
+    @Mock private lateinit var keyguardRootViewModel: KeyguardRootViewModel
+    @Mock private lateinit var indicationController: KeyguardIndicationController
+    @Mock private lateinit var featureFlags: FeatureFlags
+
+    private lateinit var underTest: DefaultIndicationAreaSection
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            DefaultIndicationAreaSection(
+                context,
+                keyguardIndicationAreaViewModel,
+                keyguardRootViewModel,
+                indicationController,
+                featureFlags,
+            )
+    }
 
     @Test
-    fun apply() {
+    fun addViewsConditionally() {
+        whenever(featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)).thenReturn(true)
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(constraintLayout)
+        assertThat(constraintLayout.childCount).isGreaterThan(0)
+    }
+
+    @Test
+    fun addViewsConditionally_migrateFlagOff() {
+        whenever(featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)).thenReturn(false)
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(constraintLayout)
+        assertThat(constraintLayout.childCount).isEqualTo(0)
+    }
+
+    @Test
+    fun applyConstraints() {
         val cs = ConstraintSet()
-        underTest.apply(cs)
+        underTest.applyConstraints(cs)
 
         val constraint = cs.getConstraint(R.id.keyguard_indication_area)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt
index 379c03c..1c3b5e61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultLockIconSectionTest.kt
@@ -19,13 +19,18 @@
 
 import android.graphics.Point
 import android.view.WindowManager
+import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.LockIconViewController
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
-import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -41,19 +46,46 @@
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var authController: AuthController
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
+    @Mock private lateinit var notificationPanelView: NotificationPanelView
+    @Mock private lateinit var featureFlags: FeatureFlags
+    @Mock private lateinit var lockIconViewController: LockIconViewController
     private lateinit var underTest: DefaultLockIconSection
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
         underTest =
-            DefaultLockIconSection(keyguardUpdateMonitor, authController, windowManager, context)
+            DefaultLockIconSection(
+                keyguardUpdateMonitor,
+                authController,
+                windowManager,
+                context,
+                notificationPanelView,
+                featureFlags,
+                lockIconViewController
+            )
     }
 
     @Test
-    fun apply() {
+    fun addViewsConditionally() {
+        whenever(featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)).thenReturn(true)
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(constraintLayout)
+        assertThat(constraintLayout.childCount).isGreaterThan(0)
+    }
+
+    @Test
+    fun addViewsConditionally_migrateFlagOff() {
+        whenever(featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON)).thenReturn(false)
+        val constraintLayout = ConstraintLayout(context, null)
+        underTest.addViews(constraintLayout)
+        assertThat(constraintLayout.childCount).isEqualTo(0)
+    }
+
+    @Test
+    fun applyConstraints() {
         val cs = ConstraintSet()
-        underTest.apply(cs)
+        underTest.applyConstraints(cs)
 
         val constraint = cs.getConstraint(R.id.lock_icon_view)
 
@@ -64,7 +96,7 @@
     @Test
     fun testCenterLockIcon() {
         val cs = ConstraintSet()
-        underTest.centerLockIcon(Point(5, 6), 1F, 5, cs)
+        underTest.centerLockIcon(Point(5, 6), 1F, cs)
 
         val constraint = cs.getConstraint(R.id.lock_icon_view)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
index 3576ec9..b935e1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelTest.kt
@@ -57,11 +57,12 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth
+import kotlin.math.max
+import kotlin.math.min
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runTest
-import org.junit.Assert.*
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -70,8 +71,6 @@
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
-import kotlin.math.max
-import kotlin.math.min
 
 @SmallTest
 @RunWith(JUnit4::class)
@@ -105,9 +104,11 @@
         overrideResource(
             R.array.config_keyguardQuickAffordanceDefaults,
             arrayOf(
-                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + ":" +
+                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START +
+                    ":" +
                     BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
-                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + ":" +
+                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END +
+                    ":" +
                     BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
             )
         )
@@ -144,16 +145,16 @@
             KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
-                mock<UserFileManager>().apply {
-                    whenever(
-                        getSharedPreferences(
-                            ArgumentMatchers.anyString(),
-                            ArgumentMatchers.anyInt(),
-                            ArgumentMatchers.anyInt(),
-                        )
-                    )
-                        .thenReturn(FakeSharedPreferences())
-                },
+                    mock<UserFileManager>().apply {
+                        whenever(
+                                getSharedPreferences(
+                                    ArgumentMatchers.anyString(),
+                                    ArgumentMatchers.anyInt(),
+                                    ArgumentMatchers.anyInt(),
+                                )
+                            )
+                            .thenReturn(FakeSharedPreferences())
+                    },
                 userTracker = userTracker,
                 broadcastDispatcher = fakeBroadcastDispatcher,
             )
@@ -172,42 +173,43 @@
                 remoteUserSelectionManager = remoteUserSelectionManager,
                 userTracker = userTracker,
                 legacySettingSyncer =
-                KeyguardQuickAffordanceLegacySettingSyncer(
-                    scope = testScope.backgroundScope,
-                    backgroundDispatcher = testDispatcher,
-                    secureSettings = FakeSettings(),
-                    selectionsManager = localUserSelectionManager,
-                ),
+                    KeyguardQuickAffordanceLegacySettingSyncer(
+                        scope = testScope.backgroundScope,
+                        backgroundDispatcher = testDispatcher,
+                        secureSettings = FakeSettings(),
+                        selectionsManager = localUserSelectionManager,
+                    ),
                 configs =
-                setOf(
-                    homeControlsQuickAffordanceConfig,
-                    quickAccessWalletAffordanceConfig,
-                    qrCodeScannerAffordanceConfig,
-                ),
+                    setOf(
+                        homeControlsQuickAffordanceConfig,
+                        quickAccessWalletAffordanceConfig,
+                        qrCodeScannerAffordanceConfig,
+                    ),
                 dumpManager = mock(),
                 userHandle = UserHandle.SYSTEM,
             )
 
-        underTest = KeyguardQuickAffordancesCombinedViewModel(
-            quickAffordanceInteractor =
-            KeyguardQuickAffordanceInteractor(
-                keyguardInteractor = keyguardInteractor,
-                lockPatternUtils = lockPatternUtils,
-                keyguardStateController = keyguardStateController,
-                userTracker = userTracker,
-                activityStarter = activityStarter,
-                featureFlags = featureFlags,
-                repository = { quickAffordanceRepository },
-                launchAnimator = launchAnimator,
-                logger = logger,
-                devicePolicyManager = devicePolicyManager,
-                dockManager = dockManager,
-                biometricSettingsRepository = biometricSettingsRepository,
-                backgroundDispatcher = testDispatcher,
-                appContext = mContext,
-            ),
-            keyguardInteractor = keyguardInteractor
-        )
+        underTest =
+            KeyguardQuickAffordancesCombinedViewModel(
+                quickAffordanceInteractor =
+                    KeyguardQuickAffordanceInteractor(
+                        keyguardInteractor = keyguardInteractor,
+                        lockPatternUtils = lockPatternUtils,
+                        keyguardStateController = keyguardStateController,
+                        userTracker = userTracker,
+                        activityStarter = activityStarter,
+                        featureFlags = featureFlags,
+                        repository = { quickAffordanceRepository },
+                        launchAnimator = launchAnimator,
+                        logger = logger,
+                        devicePolicyManager = devicePolicyManager,
+                        dockManager = dockManager,
+                        biometricSettingsRepository = biometricSettingsRepository,
+                        backgroundDispatcher = testDispatcher,
+                        appContext = mContext,
+                    ),
+                keyguardInteractor = keyguardInteractor
+            )
     }
 
     @Test
@@ -242,9 +244,8 @@
     @Test
     fun startButton_hiddenWhenDevicePolicyDisablesAllKeyguardFeatures() =
         testScope.runTest {
-            whenever(
-                devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)
-            ).thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
+            whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
+                .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
             repository.setKeyguardShowing(true)
             val latest by collectLastValue(underTest.startButton)
 
@@ -267,10 +268,10 @@
             assertQuickAffordanceViewModel(
                 viewModel = latest,
                 testConfig =
-                TestConfig(
-                    isVisible = false,
-                    slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
-                ),
+                    TestConfig(
+                        isVisible = false,
+                        slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
+                    ),
                 configKey = configKey,
             )
         }
@@ -278,9 +279,7 @@
     @Test
     fun startButton_inPreviewMode_visibleEvenWhenKeyguardNotShowing() =
         testScope.runTest {
-            underTest.onPreviewSlotSelected(
-                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
-            )
+            underTest.onPreviewSlotSelected(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START)
             underTest.enablePreviewMode(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, true)
 
             repository.setKeyguardShowing(false)
@@ -291,30 +290,30 @@
                 setUpQuickAffordanceModel(
                     position = KeyguardQuickAffordancePosition.BOTTOM_START,
                     testConfig =
-                    TestConfig(
-                        isVisible = true,
-                        isClickable = true,
-                        isActivated = true,
-                        icon = icon,
-                        canShowWhileLocked = false,
-                        intent = Intent("action"),
-                        slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
-                    ),
+                        TestConfig(
+                            isVisible = true,
+                            isClickable = true,
+                            isActivated = true,
+                            icon = icon,
+                            canShowWhileLocked = false,
+                            intent = Intent("action"),
+                            slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
+                        ),
                 )
 
             assertQuickAffordanceViewModel(
                 viewModel = latest(),
                 testConfig =
-                TestConfig(
-                    isVisible = true,
-                    isClickable = false,
-                    isActivated = false,
-                    icon = icon,
-                    canShowWhileLocked = false,
-                    intent = Intent("action"),
-                    isSelected = true,
-                    slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
-                ),
+                    TestConfig(
+                        isVisible = true,
+                        isClickable = false,
+                        isActivated = false,
+                        icon = icon,
+                        canShowWhileLocked = false,
+                        intent = Intent("action"),
+                        isSelected = true,
+                        slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
+                    ),
                 configKey = configKey,
             )
             Truth.assertThat(latest()?.isSelected).isTrue()
@@ -323,9 +322,7 @@
     @Test
     fun endButton_inHiglightedPreviewMode_dimmedWhenOtherIsSelected() =
         testScope.runTest {
-            underTest.onPreviewSlotSelected(
-                KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START
-            )
+            underTest.onPreviewSlotSelected(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START)
             underTest.enablePreviewMode(KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START, true)
 
             repository.setKeyguardShowing(false)
@@ -335,20 +332,6 @@
             setUpQuickAffordanceModel(
                 position = KeyguardQuickAffordancePosition.BOTTOM_START,
                 testConfig =
-                TestConfig(
-                    isVisible = true,
-                    isClickable = true,
-                    isActivated = true,
-                    icon = icon,
-                    canShowWhileLocked = false,
-                    intent = Intent("action"),
-                    slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
-                ),
-            )
-            val configKey =
-                setUpQuickAffordanceModel(
-                    position = KeyguardQuickAffordancePosition.BOTTOM_END,
-                    testConfig =
                     TestConfig(
                         isVisible = true,
                         isClickable = true,
@@ -356,23 +339,37 @@
                         icon = icon,
                         canShowWhileLocked = false,
                         intent = Intent("action"),
-                        slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
+                        slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId(),
                     ),
+            )
+            val configKey =
+                setUpQuickAffordanceModel(
+                    position = KeyguardQuickAffordancePosition.BOTTOM_END,
+                    testConfig =
+                        TestConfig(
+                            isVisible = true,
+                            isClickable = true,
+                            isActivated = true,
+                            icon = icon,
+                            canShowWhileLocked = false,
+                            intent = Intent("action"),
+                            slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
+                        ),
                 )
 
             assertQuickAffordanceViewModel(
                 viewModel = endButton(),
                 testConfig =
-                TestConfig(
-                    isVisible = true,
-                    isClickable = false,
-                    isActivated = false,
-                    icon = icon,
-                    canShowWhileLocked = false,
-                    intent = Intent("action"),
-                    isDimmed = true,
-                    slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
-                ),
+                    TestConfig(
+                        isVisible = true,
+                        isClickable = false,
+                        isActivated = false,
+                        icon = icon,
+                        canShowWhileLocked = false,
+                        intent = Intent("action"),
+                        isDimmed = true,
+                        slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
+                    ),
                 configKey = configKey,
             )
         }
@@ -390,7 +387,7 @@
                     icon = mock(),
                     canShowWhileLocked = false,
                     intent =
-                    null, // This will cause it to tell the system that the click was handled.
+                        null, // This will cause it to tell the system that the click was handled.
                     slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId(),
                 )
             val configKey =
@@ -610,10 +607,10 @@
                 KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                     icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
                     activationState =
-                    when (testConfig.isActivated) {
-                        true -> ActivationState.Active
-                        false -> ActivationState.Inactive
-                    }
+                        when (testConfig.isActivated) {
+                            true -> ActivationState.Active
+                            false -> ActivationState.Inactive
+                        }
                 )
             } else {
                 KeyguardQuickAffordanceConfig.LockScreenState.Hidden
@@ -644,9 +641,7 @@
                 )
             )
             if (testConfig.intent != null) {
-                Truth.assertThat(
-                    Mockito.mockingDetails(activityStarter).invocations
-                ).hasSize(1)
+                Truth.assertThat(Mockito.mockingDetails(activityStarter).invocations).hasSize(1)
             } else {
                 Mockito.verifyZeroInteractions(activityStarter)
             }
@@ -670,4 +665,4 @@
             check(!isVisible || icon != null) { "Must supply non-null icon if visible!" }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index a9f288d..b30dc9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -23,15 +23,13 @@
 import com.android.systemui.scene.SceneTestUtils
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.util.mockito.mock
 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
 import org.junit.runners.JUnit4
 
-@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(JUnit4::class)
 class LockscreenSceneViewModelTest : SysuiTestCase() {
@@ -47,10 +45,9 @@
     private val underTest =
         LockscreenSceneViewModel(
             authenticationInteractor = authenticationInteractor,
-            bouncerInteractor =
-                utils.bouncerInteractor(
-                    authenticationInteractor = authenticationInteractor,
-                    sceneInteractor = sceneInteractor,
+            longPress =
+                KeyguardLongPressViewModel(
+                    interactor = mock(),
                 ),
         )
 
@@ -76,30 +73,4 @@
 
             assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
         }
-
-    @Test
-    fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
-        testScope.runTest {
-            val currentScene by collectLastValue(sceneInteractor.desiredScene)
-            utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
-            utils.authenticationRepository.setUnlocked(false)
-            runCurrent()
-
-            underTest.onLockButtonClicked()
-
-            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
-        }
-
-    @Test
-    fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
-        testScope.runTest {
-            val currentScene by collectLastValue(sceneInteractor.desiredScene)
-            utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
-            utils.authenticationRepository.setUnlocked(true)
-            runCurrent()
-
-            underTest.onLockButtonClicked()
-
-            assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
-        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index ef51e47..3961a94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -33,7 +33,6 @@
 import com.android.keyguard.TestScopeProvider
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -105,7 +104,6 @@
     @Mock @Main private lateinit var executor: DelayableExecutor
     @Mock lateinit var mediaDataManager: MediaDataManager
     @Mock lateinit var configurationController: ConfigurationController
-    @Mock lateinit var falsingCollector: FalsingCollector
     @Mock lateinit var falsingManager: FalsingManager
     @Mock lateinit var dumpManager: DumpManager
     @Mock lateinit var logger: MediaUiEventLogger
@@ -146,7 +144,6 @@
                 executor,
                 mediaDataManager,
                 configurationController,
-                falsingCollector,
                 falsingManager,
                 dumpManager,
                 logger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
new file mode 100644
index 0000000..49f536e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.controls.ui
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.media.controls.util.MediaUiEventLogger
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.PageIndicator
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner::class)
+class MediaCarouselScrollHandlerTest : SysuiTestCase() {
+
+    private val carouselWidth = 1038
+    private val motionEventUp = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0f, 0f, 0)
+
+    @Mock lateinit var mediaCarousel: MediaScrollView
+    @Mock lateinit var pageIndicator: PageIndicator
+    @Mock lateinit var dismissCallback: () -> Unit
+    @Mock lateinit var translationChangedListener: () -> Unit
+    @Mock lateinit var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit
+    @Mock lateinit var closeGuts: (immediate: Boolean) -> Unit
+    @Mock lateinit var falsingManager: FalsingManager
+    @Mock lateinit var logSmartspaceImpression: (Boolean) -> Unit
+    @Mock lateinit var logger: MediaUiEventLogger
+
+    lateinit var executor: FakeExecutor
+    private val clock = FakeSystemClock()
+
+    private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        executor = FakeExecutor(clock)
+        mediaCarouselScrollHandler =
+            MediaCarouselScrollHandler(
+                mediaCarousel,
+                pageIndicator,
+                executor,
+                dismissCallback,
+                translationChangedListener,
+                seekBarUpdateListener,
+                closeGuts,
+                falsingManager,
+                logSmartspaceImpression,
+                logger
+            )
+        mediaCarouselScrollHandler.playerWidthPlusPadding = carouselWidth
+
+        whenever(mediaCarousel.touchListener).thenReturn(mediaCarouselScrollHandler.touchListener)
+    }
+
+    @Test
+    fun testCarouselScroll_shortScroll() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(false)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(300)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(0), anyInt())
+    }
+
+    @Test
+    fun testCarouselScroll_shortScroll_isRTL() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(true)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(300)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(carouselWidth), anyInt())
+    }
+
+    @Test
+    fun testCarouselScroll_longScroll() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(false)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(600)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(carouselWidth), anyInt())
+    }
+
+    @Test
+    fun testCarouselScroll_longScroll_isRTL() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(true)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(600)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(0), anyInt())
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 338182a..b9ee19b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -36,6 +36,8 @@
 import android.os.PowerManager;
 import android.os.Temperature;
 import android.provider.Settings;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -50,20 +52,17 @@
 import com.android.systemui.power.PowerUI.WarningsUI;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.time.Duration;
-import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
-import dagger.Lazy;
-
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -93,15 +92,12 @@
     private IThermalEventListener mSkinThermalEventListener;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private CommandQueue mCommandQueue;
-    @Mock private Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
-    @Mock private CentralSurfaces mCentralSurfaces;
+    @Mock private IVrManager mVrManager;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        when(mCentralSurfacesOptionalLazy.get()).thenReturn(Optional.of(mCentralSurfaces));
-
         createPowerUi();
         mSkinThermalEventListener = mPowerUI.new SkinThermalEventListener();
         mUsbThermalEventListener = mPowerUI.new UsbThermalEventListener();
@@ -143,6 +139,23 @@
     }
 
     @Test
+    public void testSkinWarning_throttlingEmergency_butVrMode() throws Exception {
+        mPowerUI.start();
+
+        ArgumentCaptor<IVrStateCallbacks> vrCallback =
+                ArgumentCaptor.forClass(IVrStateCallbacks.class);
+        verify(mVrManager).registerListener(vrCallback.capture());
+
+        vrCallback.getValue().onVrStateChanged(true);
+        final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_SKIN, "skin2");
+        mSkinThermalEventListener.notifyThrottling(temp);
+
+        TestableLooper.get(this).processAllMessages();
+        // don't show skin high temperature warning when in VR mode
+        verify(mMockWarnings, never()).showHighTemperatureWarning();
+    }
+
+    @Test
     public void testUsbAlarm_throttlingCritical() throws Exception {
         mPowerUI.start();
 
@@ -683,8 +696,14 @@
 
     private void createPowerUi() {
         mPowerUI = new PowerUI(
-                mContext, mBroadcastDispatcher, mCommandQueue, mCentralSurfacesOptionalLazy,
-                mMockWarnings, mEnhancedEstimates, mWakefulnessLifecycle, mPowerManager,
+                mContext,
+                mBroadcastDispatcher,
+                mCommandQueue,
+                mVrManager,
+                mMockWarnings,
+                mEnhancedEstimates,
+                mWakefulnessLifecycle,
+                mPowerManager,
                 mUserTracker);
         mPowerUI.mThermalService = mThermalServiceMock;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
index a01394f..f566efe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/PowerRepositoryImplTest.kt
@@ -193,6 +193,23 @@
         assertThat(reasonCaptor.value).contains(context.applicationContext.packageName)
     }
 
+    @Test
+    fun userActivity_notifiesPowerManager() {
+        systemClock.setUptimeMillis(345000)
+
+        underTest.userTouch()
+
+        val flagsCaptor = argumentCaptor<Int>()
+        verify(manager)
+            .userActivity(
+                eq(345000L),
+                eq(PowerManager.USER_ACTIVITY_EVENT_TOUCH),
+                capture(flagsCaptor)
+            )
+        assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS)
+        assertThat(flagsCaptor.value).isNotEqualTo(PowerManager.USER_ACTIVITY_FLAG_INDIRECT)
+    }
+
     private fun verifyRegistered() {
         // We must verify with all arguments, even those that are optional because they have default
         // values because Mockito is forcing us to. Once we can use mockito-kotlin, we should be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 93ed994..e537131 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import static com.android.systemui.flags.Flags.SIGNAL_CALLBACK_DEPRECATION;
+
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.TestCase.assertEquals;
 
@@ -37,9 +39,11 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
@@ -49,6 +53,12 @@
 import com.android.systemui.statusbar.connectivity.NetworkController;
 import com.android.systemui.statusbar.connectivity.SignalCallback;
 import com.android.systemui.statusbar.connectivity.WifiIndicators;
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository;
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository;
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor;
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl;
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel;
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel.Inactive;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -65,6 +75,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import kotlinx.coroutines.test.TestScope;
 
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -98,6 +109,12 @@
     @Mock
     private QsEventLogger mUiEventLogger;
 
+    private WifiInteractor mWifiInteractor;
+    private final TileJavaAdapter mJavaAdapter = new TileJavaAdapter();
+    private final FakeWifiRepository mWifiRepository = new FakeWifiRepository();
+    private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
+    private final TestScope mTestScope = TestScopeProvider.getTestScope();
+
     private TestableLooper mTestableLooper;
     private CastTile mCastTile;
 
@@ -108,42 +125,11 @@
 
         when(mHost.getContext()).thenReturn(mContext);
 
-        mCastTile = new CastTile(
-                mHost,
-                mUiEventLogger,
-                mTestableLooper.getLooper(),
-                new Handler(mTestableLooper.getLooper()),
-                new FalsingManagerFake(),
-                mMetricsLogger,
-                mStatusBarStateController,
-                mActivityStarter,
-                mQSLogger,
-                mController,
-                mKeyguard,
-                mNetworkController,
-                mHotspotController,
-                mDialogLaunchAnimator
+        mWifiInteractor = new WifiInteractorImpl(
+                new FakeConnectivityRepository(),
+                mWifiRepository,
+                mTestScope
         );
-        mCastTile.initialize();
-
-        // We are not setting the mocks to listening, so we trigger a first refresh state to
-        // set the initial state
-        mCastTile.refreshState();
-
-        mTestableLooper.processAllMessages();
-
-        mCastTile.handleSetListening(true);
-        ArgumentCaptor<SignalCallback> signalCallbackArgumentCaptor =
-                ArgumentCaptor.forClass(SignalCallback.class);
-        verify(mNetworkController).observe(any(LifecycleOwner.class),
-                signalCallbackArgumentCaptor.capture());
-        mSignalCallback = signalCallbackArgumentCaptor.getValue();
-
-        ArgumentCaptor<HotspotController.Callback> hotspotCallbackArgumentCaptor =
-                ArgumentCaptor.forClass(HotspotController.Callback.class);
-        verify(mHotspotController).observe(any(LifecycleOwner.class),
-                hotspotCallbackArgumentCaptor.capture());
-        mHotspotCallback = hotspotCallbackArgumentCaptor.getValue();
     }
 
     @After
@@ -156,10 +142,11 @@
     // All these tests for enabled/disabled wifi have hotspot not enabled
     @Test
     public void testStateUnavailable_wifiDisabled() {
+        createAndStartTileOldImpl();
         IconState qsIcon = new IconState(false, 0, "");
         WifiIndicators indicators = new WifiIndicators(
                 false, mock(IconState.class),
-                qsIcon, false,false, "",
+                qsIcon, false, false, "",
                 false, "");
         mSignalCallback.setWifiIndicators(indicators);
         mTestableLooper.processAllMessages();
@@ -169,10 +156,11 @@
 
     @Test
     public void testStateUnavailable_wifiNotConnected() {
+        createAndStartTileOldImpl();
         IconState qsIcon = new IconState(false, 0, "");
         WifiIndicators indicators = new WifiIndicators(
                 true, mock(IconState.class),
-                qsIcon, false,false, "",
+                qsIcon, false, false, "",
                 false, "");
         mSignalCallback.setWifiIndicators(indicators);
         mTestableLooper.processAllMessages();
@@ -184,7 +172,7 @@
         IconState qsIcon = new IconState(true, 0, "");
         WifiIndicators indicators = new WifiIndicators(
                 true, mock(IconState.class),
-                qsIcon, false,false, "",
+                qsIcon, false, false, "",
                 false, "");
         mSignalCallback.setWifiIndicators(indicators);
         mTestableLooper.processAllMessages();
@@ -192,6 +180,7 @@
 
     @Test
     public void testStateActive_wifiEnabledAndCasting() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastController.CastDevice.STATE_CONNECTED;
         List<CastDevice> devices = new ArrayList<>();
@@ -204,15 +193,87 @@
 
     @Test
     public void testStateInactive_wifiEnabledNotCasting() {
+        createAndStartTileOldImpl();
         enableWifiAndProcessMessages();
         assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
     }
     // -------------------------------------------------
 
     // -------------------------------------------------
+    // All these tests for enabled/disabled wifi have hotspot not enabled, and have the
+    // SIGNAL_CALLBACK_DEPRECATION flag set to true
+
+    @Test
+    public void stateUnavailable_wifiDisabled_newPipeline() {
+        createAndStartTileNewImpl();
+        mWifiRepository.setIsWifiEnabled(false);
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+    }
+
+    @Test
+    public void stateUnavailable_wifiEnabled_notConnected_newPipeline() {
+        createAndStartTileNewImpl();
+        mWifiRepository.setIsWifiEnabled(true);
+        mWifiRepository.setWifiNetwork(Inactive.INSTANCE);
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+    }
+
+    @Test
+    public void stateActive_wifiConnectedAndCasting_newPipeline() {
+        createAndStartTileNewImpl();
+        CastController.CastDevice device = new CastController.CastDevice();
+        device.state = CastDevice.STATE_CONNECTED;
+        List<CastDevice> devices = new ArrayList<>();
+        devices.add(device);
+        when(mController.getCastDevices()).thenReturn(devices);
+
+        mWifiRepository.setWifiNetwork(
+                new WifiNetworkModel.Active(
+                        1 /* networkId */,
+                        true /* isValidated */,
+                        3 /* level */,
+                        "test" /* ssid */,
+                        WifiNetworkModel.HotspotDeviceType.NONE,
+                        false /* isPasspointAccessPoint */,
+                        false /* isOnlineSignUpforPasspointAccessPoint */,
+                        null /* passpointProviderFriendlyName */
+                ));
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
+    }
+
+    @Test
+    public void stateInactive_wifiConnectedNotCasting_newPipeline() {
+        createAndStartTileNewImpl();
+
+        mWifiRepository.setWifiNetwork(
+                new WifiNetworkModel.Active(
+                        1 /* networkId */,
+                        true /* isValidated */,
+                        3 /* level */,
+                        "test" /* ssid */,
+                        WifiNetworkModel.HotspotDeviceType.NONE,
+                        false /* isPasspointAccessPoint */,
+                        false /* isOnlineSignUpforPasspointAccessPoint */,
+                        null /* passpointProviderFriendlyName */
+                ));
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
+    }
+
+    // -------------------------------------------------
+
+    // -------------------------------------------------
     // All these tests for enabled/disabled hotspot have wifi not enabled
     @Test
     public void testStateUnavailable_hotspotDisabled() {
+        createAndStartTileOldImpl();
         mHotspotCallback.onHotspotChanged(false, 0);
         mTestableLooper.processAllMessages();
 
@@ -221,6 +282,7 @@
 
     @Test
     public void testStateUnavailable_hotspotEnabledNotConnected() {
+        createAndStartTileOldImpl();
         mHotspotCallback.onHotspotChanged(true, 0);
         mTestableLooper.processAllMessages();
 
@@ -229,6 +291,7 @@
 
     @Test
     public void testStateActive_hotspotEnabledAndConnectedAndCasting() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastController.CastDevice.STATE_CONNECTED;
         List<CastDevice> devices = new ArrayList<>();
@@ -242,6 +305,7 @@
 
     @Test
     public void testStateInactive_hotspotEnabledAndConnectedAndNotCasting() {
+        createAndStartTileOldImpl();
         mHotspotCallback.onHotspotChanged(true, 1);
         mTestableLooper.processAllMessages();
         assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
@@ -250,6 +314,7 @@
 
     @Test
     public void testHandleClick_castDevicePresent() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastDevice.STATE_CONNECTED;
         device.tag = mock(MediaRouter.RouteInfo.class);
@@ -267,6 +332,7 @@
 
     @Test
     public void testHandleClick_projectionOnly() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastDevice.STATE_CONNECTED;
         device.tag = mock(MediaProjectionInfo.class);
@@ -283,6 +349,7 @@
 
     @Test
     public void testUpdateState_projectionOnly() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastDevice.STATE_CONNECTED;
         device.tag = mock(MediaProjectionInfo.class);
@@ -298,6 +365,7 @@
 
     @Test
     public void testUpdateState_castingAndProjection() {
+        createAndStartTileOldImpl();
         CastController.CastDevice casting = new CastController.CastDevice();
         casting.state = CastDevice.STATE_CONNECTED;
         casting.tag = mock(RouteInfo.class);
@@ -322,6 +390,7 @@
 
     @Test
     public void testUpdateState_connectedAndConnecting() {
+        createAndStartTileOldImpl();
         CastController.CastDevice connecting = new CastController.CastDevice();
         connecting.state = CastDevice.STATE_CONNECTING;
         connecting.tag = mock(RouteInfo.class);
@@ -346,6 +415,7 @@
 
     @Test
     public void testExpandView_wifiNotConnected() {
+        createAndStartTileOldImpl();
         mCastTile.refreshState();
         mTestableLooper.processAllMessages();
 
@@ -354,6 +424,7 @@
 
     @Test
     public void testExpandView_wifiEnabledNotCasting() {
+        createAndStartTileOldImpl();
         enableWifiAndProcessMessages();
 
         assertTrue(mCastTile.getState().forceExpandIcon);
@@ -361,6 +432,7 @@
 
     @Test
     public void testExpandView_casting_projection() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastController.CastDevice.STATE_CONNECTED;
         List<CastDevice> devices = new ArrayList<>();
@@ -374,6 +446,7 @@
 
     @Test
     public void testExpandView_connecting_projection() {
+        createAndStartTileOldImpl();
         CastController.CastDevice connecting = new CastController.CastDevice();
         connecting.state = CastDevice.STATE_CONNECTING;
         connecting.name = "Test Casting Device";
@@ -389,6 +462,7 @@
 
     @Test
     public void testExpandView_casting_mediaRoute() {
+        createAndStartTileOldImpl();
         CastController.CastDevice device = new CastController.CastDevice();
         device.state = CastDevice.STATE_CONNECTED;
         device.tag = mock(MediaRouter.RouteInfo.class);
@@ -403,6 +477,7 @@
 
     @Test
     public void testExpandView_connecting_mediaRoute() {
+        createAndStartTileOldImpl();
         CastController.CastDevice connecting = new CastController.CastDevice();
         connecting.state = CastDevice.STATE_CONNECTING;
         connecting.tag = mock(RouteInfo.class);
@@ -416,4 +491,86 @@
 
         assertTrue(mCastTile.getState().forceExpandIcon);
     }
+
+    /**
+     * For simplicity, let this method still set the field even though that's kind of gross
+     */
+    private void createAndStartTileOldImpl() {
+        mFeatureFlags.set(SIGNAL_CALLBACK_DEPRECATION, false);
+        mCastTile = new CastTile(
+                mHost,
+                mUiEventLogger,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mController,
+                mKeyguard,
+                mNetworkController,
+                mHotspotController,
+                mDialogLaunchAnimator,
+                mWifiInteractor,
+                mJavaAdapter,
+                mFeatureFlags
+        );
+        mCastTile.initialize();
+
+        // We are not setting the mocks to listening, so we trigger a first refresh state to
+        // set the initial state
+        mCastTile.refreshState();
+
+        mTestableLooper.processAllMessages();
+
+        mCastTile.handleSetListening(true);
+        ArgumentCaptor<SignalCallback> signalCallbackArgumentCaptor =
+                ArgumentCaptor.forClass(SignalCallback.class);
+        verify(mNetworkController).observe(any(LifecycleOwner.class),
+                signalCallbackArgumentCaptor.capture());
+        mSignalCallback = signalCallbackArgumentCaptor.getValue();
+
+        ArgumentCaptor<HotspotController.Callback> hotspotCallbackArgumentCaptor =
+                ArgumentCaptor.forClass(HotspotController.Callback.class);
+        verify(mHotspotController).observe(any(LifecycleOwner.class),
+                hotspotCallbackArgumentCaptor.capture());
+        mHotspotCallback = hotspotCallbackArgumentCaptor.getValue();
+    }
+
+    private void createAndStartTileNewImpl() {
+        mFeatureFlags.set(SIGNAL_CALLBACK_DEPRECATION, true);
+        mCastTile = new CastTile(
+                mHost,
+                mUiEventLogger,
+                mTestableLooper.getLooper(),
+                new Handler(mTestableLooper.getLooper()),
+                new FalsingManagerFake(),
+                mMetricsLogger,
+                mStatusBarStateController,
+                mActivityStarter,
+                mQSLogger,
+                mController,
+                mKeyguard,
+                mNetworkController,
+                mHotspotController,
+                mDialogLaunchAnimator,
+                mWifiInteractor,
+                mJavaAdapter,
+                mFeatureFlags
+        );
+        mCastTile.initialize();
+
+        // Since we do not capture the callbacks like in the old impl, set the state to RESUMED
+        // So that TileJavaAdapter is collecting on flows
+        mCastTile.setListening(new Object(), true);
+
+        mTestableLooper.processAllMessages();
+
+        ArgumentCaptor<HotspotController.Callback> hotspotCallbackArgumentCaptor =
+                ArgumentCaptor.forClass(HotspotController.Callback.class);
+        verify(mHotspotController).observe(any(LifecycleOwner.class),
+                hotspotCallbackArgumentCaptor.capture());
+        mHotspotCallback = hotspotCallbackArgumentCaptor.getValue();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
new file mode 100644
index 0000000..b6cf459
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles
+
+import android.os.Handler
+import android.service.quicksettings.Tile
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.QSHost
+import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.tiles.dialog.InternetDialogFactory
+import com.android.systemui.statusbar.connectivity.AccessPointController
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel.Wifi
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.InternetTileViewModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWithLooper(setAsMainLooper = true)
+class InternetTileNewImplTest : SysuiTestCase() {
+    lateinit var underTest: InternetTileNewImpl
+
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private var airplaneModeRepository = FakeAirplaneModeRepository()
+    private var connectivityRepository = FakeConnectivityRepository()
+    private var ethernetInteractor = EthernetInteractor(connectivityRepository)
+    private var mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+    private var wifiRepository = FakeWifiRepository()
+    private var wifiInteractor =
+        WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope)
+    private lateinit var viewModel: InternetTileViewModel
+
+    private lateinit var looper: TestableLooper
+
+    @Mock private lateinit var host: QSHost
+    @Mock private lateinit var eventLogger: QsEventLogger
+    @Mock private lateinit var metricsLogger: MetricsLogger
+    @Mock private lateinit var sbStateController: StatusBarStateController
+    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var logger: QSLogger
+    @Mock private lateinit var dialogFactory: InternetDialogFactory
+    @Mock private lateinit var accessPointController: AccessPointController
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        looper = TestableLooper.get(this)
+
+        // Allow the tile to load resources
+        whenever(host.context).thenReturn(context)
+        whenever(host.userContext).thenReturn(context)
+
+        viewModel =
+            InternetTileViewModel(
+                airplaneModeRepository,
+                connectivityRepository,
+                ethernetInteractor,
+                mobileIconsInteractor,
+                wifiInteractor,
+                context,
+                testScope.backgroundScope,
+            )
+
+        underTest =
+            InternetTileNewImpl(
+                host,
+                eventLogger,
+                looper.looper,
+                Handler(looper.looper),
+                FalsingManagerFake(),
+                metricsLogger,
+                sbStateController,
+                activityStarter,
+                logger,
+                viewModel,
+                dialogFactory,
+                accessPointController
+            )
+
+        underTest.initialize()
+        underTest.setListening(Object(), true)
+
+        looper.processAllMessages()
+    }
+
+    @Test
+    fun noDefaultConnection_noNetworkAvailable() =
+        testScope.runTest {
+            connectivityRepository.defaultConnections.value = DefaultConnectionModel()
+            wifiRepository.wifiScanResults.value = listOf()
+
+            runCurrent()
+            looper.processAllMessages()
+
+            assertThat(underTest.state.secondaryLabel.toString())
+                .isEqualTo(context.getString(R.string.quick_settings_networks_unavailable))
+            assertThat(underTest.state.state).isEqualTo(Tile.STATE_INACTIVE)
+        }
+
+    @Test
+    fun noDefaultConnection_networksAvailable() =
+        testScope.runTest {
+            connectivityRepository.defaultConnections.value = DefaultConnectionModel()
+            wifiRepository.wifiScanResults.value =
+                listOf(
+                    WifiScanEntry(ssid = "ssid 1"),
+                    WifiScanEntry(ssid = "ssid 2"),
+                )
+
+            runCurrent()
+            looper.processAllMessages()
+
+            assertThat(underTest.state.secondaryLabel.toString())
+                .isEqualTo(context.getString(R.string.quick_settings_networks_available))
+            assertThat(underTest.state.state).isEqualTo(1)
+        }
+
+    @Test
+    fun airplaneMode_enabled_wifiDisabled() =
+        testScope.runTest {
+            airplaneModeRepository.setIsAirplaneMode(true)
+            connectivityRepository.defaultConnections.value = DefaultConnectionModel()
+            wifiRepository.setIsWifiEnabled(false)
+
+            runCurrent()
+            looper.processAllMessages()
+
+            assertThat(underTest.state.state).isEqualTo(Tile.STATE_INACTIVE)
+            assertThat(underTest.state.secondaryLabel)
+                .isEqualTo(context.getString(R.string.status_bar_airplane))
+        }
+
+    @Test
+    fun airplaneMode_enabled_wifiEnabledButNotConnected() =
+        testScope.runTest {
+            airplaneModeRepository.setIsAirplaneMode(true)
+            connectivityRepository.defaultConnections.value = DefaultConnectionModel()
+            wifiRepository.setIsWifiEnabled(true)
+
+            runCurrent()
+            looper.processAllMessages()
+
+            assertThat(underTest.state.state).isEqualTo(Tile.STATE_INACTIVE)
+            assertThat(underTest.state.secondaryLabel)
+                .isEqualTo(context.getString(R.string.status_bar_airplane))
+        }
+
+    @Test
+    fun airplaneMode_enabled_wifiEnabledAndConnected() =
+        testScope.runTest {
+            airplaneModeRepository.setIsAirplaneMode(true)
+            connectivityRepository.defaultConnections.value =
+                DefaultConnectionModel(
+                    wifi = Wifi(true),
+                    isValidated = true,
+                )
+            wifiRepository.setIsWifiEnabled(true)
+            wifiRepository.setWifiNetwork(ACTIVE_WIFI)
+
+            runCurrent()
+            looper.processAllMessages()
+
+            assertThat(underTest.state.state).isEqualTo(Tile.STATE_ACTIVE)
+            assertThat(underTest.state.secondaryLabel).isEqualTo(WIFI_SSID)
+        }
+
+    @Test
+    fun wifiConnected() =
+        testScope.runTest {
+            connectivityRepository.defaultConnections.value =
+                DefaultConnectionModel(
+                    wifi = Wifi(true),
+                    isValidated = true,
+                )
+
+            wifiRepository.setIsWifiEnabled(true)
+            wifiRepository.setWifiNetwork(ACTIVE_WIFI)
+
+            runCurrent()
+            looper.processAllMessages()
+
+            assertThat(underTest.state.state).isEqualTo(Tile.STATE_ACTIVE)
+            assertThat(underTest.state.secondaryLabel).isEqualTo(WIFI_SSID)
+        }
+
+    companion object {
+        const val WIFI_SSID = "test ssid"
+        val ACTIVE_WIFI =
+            WifiNetworkModel.Active(
+                networkId = 1,
+                isValidated = true,
+                level = 4,
+                ssid = WIFI_SSID,
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index 2cb0205..8ae8930 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -23,10 +23,19 @@
 import com.android.systemui.scene.SceneTestUtils
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
 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.junit.runners.JUnit4
@@ -44,15 +53,49 @@
             repository = utils.authenticationRepository(),
         )
 
-    private val underTest =
-        QuickSettingsSceneViewModel(
-            bouncerInteractor =
-                utils.bouncerInteractor(
-                    authenticationInteractor = authenticationInteractor,
-                    sceneInteractor = sceneInteractor,
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
                 ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
         )
 
+    private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
+
+    private lateinit var underTest: QuickSettingsSceneViewModel
+
+    @Before
+    fun setUp() {
+        shadeHeaderViewModel =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+
+        underTest =
+            QuickSettingsSceneViewModel(
+                bouncerInteractor =
+                    utils.bouncerInteractor(
+                        authenticationInteractor = authenticationInteractor,
+                        sceneInteractor = sceneInteractor,
+                    ),
+                shadeHeaderViewModel = shadeHeaderViewModel,
+            )
+    }
+
     @Test
     fun onContentClicked_deviceUnlocked_switchesToGone() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index ef07fab..e353a53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.navigationbar.NavigationBarController
 import com.android.systemui.navigationbar.NavigationModeController
 import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.settings.FakeDisplayTracker
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shade.ShadeViewController
@@ -146,6 +147,7 @@
                 sysuiUnlockAnimationController,
                 assistUtils,
                 featureFlags,
+                FakeSceneContainerFlags(),
                 dumpManager,
                 unfoldTransitionProgressForwarder
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 46cbfac..141fcbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -25,9 +25,8 @@
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
 import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.shared.model.WakefulnessState
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
 import com.android.systemui.model.SysUiState
 import com.android.systemui.scene.SceneTestUtils.Companion.toDataLayer
@@ -37,7 +36,14 @@
 import com.android.systemui.scene.shared.model.SceneModel
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.settings.FakeDisplayTracker
+import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
 import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
@@ -99,7 +105,8 @@
         )
     private val sceneContainerViewModel =
         SceneContainerViewModel(
-                interactor = sceneInteractor,
+                sceneInteractor = sceneInteractor,
+                falsingInteractor = utils.falsingInteractor(),
             )
             .apply { setTransitionState(transitionState) }
 
@@ -117,17 +124,32 @@
     private val lockscreenSceneViewModel =
         LockscreenSceneViewModel(
             authenticationInteractor = authenticationInteractor,
-            bouncerInteractor = bouncerInteractor,
+            longPress =
+                KeyguardLongPressViewModel(
+                    interactor = mock(),
+                ),
         )
 
-    private val shadeSceneViewModel =
-        ShadeSceneViewModel(
-            applicationScope = testScope.backgroundScope,
-            authenticationInteractor = authenticationInteractor,
-            bouncerInteractor = bouncerInteractor,
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
+                ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
         )
 
-    private val keyguardRepository = utils.keyguardRepository()
+    private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
+    private lateinit var shadeSceneViewModel: ShadeSceneViewModel
+
+    private val keyguardRepository = utils.keyguardRepository
     private val keyguardInteractor =
         utils.keyguardInteractor(
             repository = keyguardRepository,
@@ -135,7 +157,23 @@
 
     @Before
     fun setUp() {
-        val featureFlags = FakeFeatureFlags().apply { set(Flags.SCENE_CONTAINER, true) }
+        shadeHeaderViewModel =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+
+        shadeSceneViewModel =
+            ShadeSceneViewModel(
+                applicationScope = testScope.backgroundScope,
+                authenticationInteractor = authenticationInteractor,
+                bouncerInteractor = bouncerInteractor,
+                shadeHeaderViewModel = shadeHeaderViewModel,
+            )
 
         authenticationRepository.setUnlocked(false)
 
@@ -147,10 +185,11 @@
                 sceneInteractor = sceneInteractor,
                 authenticationInteractor = authenticationInteractor,
                 keyguardInteractor = keyguardInteractor,
-                featureFlags = featureFlags,
+                flags = utils.sceneContainerFlags,
                 sysUiState = sysUiState,
                 displayId = displayTracker.defaultDisplayId,
                 sceneLogger = mock(),
+                falsingCollector = utils.falsingCollector(),
             )
         startable.start()
 
@@ -165,9 +204,7 @@
     @Test
     fun clickLockButtonAndEnterCorrectPin_unlocksDevice() =
         testScope.runTest {
-            lockscreenSceneViewModel.onLockButtonClicked()
-            assertCurrentScene(SceneKey.Bouncer)
-            emulateUiSceneTransition()
+            emulateUserDrivenTransition(SceneKey.Bouncer)
 
             enterPin()
             assertCurrentScene(SceneKey.Gone)
@@ -460,10 +497,7 @@
             .that(authenticationInteractor.isUnlocked.value)
             .isFalse()
 
-        lockscreenSceneViewModel.onLockButtonClicked()
-        runCurrent()
-        emulateUiSceneTransition()
-
+        emulateUserDrivenTransition(SceneKey.Bouncer)
         enterPin()
         emulateUiSceneTransition(
             expectedVisible = false,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt
new file mode 100644
index 0000000..2187f36
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/WindowRootViewVisibilityRepositoryTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.IStatusBarService
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.Mockito.verify
+
+@SmallTest
+class WindowRootViewVisibilityRepositoryTest : SysuiTestCase() {
+    private val iStatusBarService = mock<IStatusBarService>()
+    private val executor = FakeExecutor(FakeSystemClock())
+    private val underTest = WindowRootViewVisibilityRepository(iStatusBarService, executor)
+
+    @Test
+    fun isLockscreenOrShadeVisible_true() {
+        underTest.setIsLockscreenOrShadeVisible(true)
+
+        assertThat(underTest.isLockscreenOrShadeVisible.value).isTrue()
+    }
+
+    @Test
+    fun isLockscreenOrShadeVisible_false() {
+        underTest.setIsLockscreenOrShadeVisible(false)
+
+        assertThat(underTest.isLockscreenOrShadeVisible.value).isFalse()
+    }
+
+    @Test
+    fun onLockscreenOrShadeInteractive_statusBarServiceNotified() {
+        underTest.onLockscreenOrShadeInteractive(
+            shouldClearNotificationEffects = true,
+            notificationCount = 3,
+        )
+        executor.runAllReady()
+
+        verify(iStatusBarService).onPanelRevealed(true, 3)
+    }
+
+    @Test
+    fun onLockscreenOrShadeNotInteractive_statusBarServiceNotified() {
+        underTest.onLockscreenOrShadeNotInteractive()
+        executor.runAllReady()
+
+        verify(iStatusBarService).onPanelHidden()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 713c602..ed716a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -28,6 +28,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -136,6 +137,97 @@
         }
 
     @Test
+    fun transitioning_idle_false() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(SceneKey.Shade)
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isFalse()
+        }
+
+    @Test
+    fun transitioning_wrongFromScene_false() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Gone,
+                        toScene = SceneKey.Lockscreen,
+                        progress = flowOf(0.5f)
+                    )
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isFalse()
+        }
+
+    @Test
+    fun transitioning_wrongToScene_false() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Shade,
+                        toScene = SceneKey.QuickSettings,
+                        progress = flowOf(0.5f)
+                    )
+                )
+            underTest.setTransitionState(transitionState)
+
+            assertThat(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen).value).isFalse()
+        }
+
+    @Test
+    fun transitioning_correctFromAndToScenes_true() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Shade,
+                        toScene = SceneKey.Lockscreen,
+                        progress = flowOf(0.5f)
+                    )
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isTrue()
+        }
+
+    @Test
+    fun transitioning_updates() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(SceneKey.Shade)
+                )
+            val transitioning by
+                collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
+            underTest.setTransitionState(transitionState)
+
+            assertThat(transitioning).isFalse()
+
+            transitionState.value =
+                ObservableTransitionState.Transition(
+                    fromScene = SceneKey.Shade,
+                    toScene = SceneKey.Lockscreen,
+                    progress = flowOf(0.5f)
+                )
+            assertThat(transitioning).isTrue()
+
+            transitionState.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
+            assertThat(transitioning).isFalse()
+        }
+
+    @Test
     fun isVisible() =
         testScope.runTest {
             val isVisible by collectLastValue(underTest.isVisible)
@@ -147,4 +239,11 @@
             underTest.setVisible(true, "reason")
             assertThat(isVisible).isTrue()
         }
+
+    @Test
+    fun userInput() =
+        testScope.runTest {
+            underTest.onUserInput()
+            assertThat(utils.powerRepository.userTouchRegistered).isTrue()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
new file mode 100644
index 0000000..f304435
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractorTest.kt
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.IStatusBarService
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.init.NotificationsController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+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.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.verify
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class WindowRootViewVisibilityInteractorTest : SysuiTestCase() {
+
+    private val testScope = TestScope()
+    private val iStatusBarService = mock<IStatusBarService>()
+    private val executor = FakeExecutor(FakeSystemClock())
+    private val windowRootViewVisibilityRepository =
+        WindowRootViewVisibilityRepository(iStatusBarService, executor)
+    private val keyguardRepository = FakeKeyguardRepository()
+    private val headsUpManager = mock<HeadsUpManager>()
+    private val notificationPresenter = mock<NotificationPresenter>()
+    private val notificationsController = mock<NotificationsController>()
+
+    private val underTest =
+        WindowRootViewVisibilityInteractor(
+                testScope.backgroundScope,
+                windowRootViewVisibilityRepository,
+                keyguardRepository,
+                headsUpManager,
+            )
+            .apply { setUp(notificationPresenter, notificationsController) }
+
+    @Test
+    fun isLockscreenOrShadeVisible_true() {
+        underTest.setIsLockscreenOrShadeVisible(true)
+
+        assertThat(underTest.isLockscreenOrShadeVisible.value).isTrue()
+    }
+
+    @Test
+    fun isLockscreenOrShadeVisible_false() {
+        underTest.setIsLockscreenOrShadeVisible(false)
+
+        assertThat(underTest.isLockscreenOrShadeVisible.value).isFalse()
+    }
+
+    @Test
+    fun isLockscreenOrShadeVisible_matchesRepo() {
+        windowRootViewVisibilityRepository.setIsLockscreenOrShadeVisible(true)
+
+        assertThat(underTest.isLockscreenOrShadeVisible.value).isTrue()
+
+        windowRootViewVisibilityRepository.setIsLockscreenOrShadeVisible(false)
+
+        assertThat(underTest.isLockscreenOrShadeVisible.value).isFalse()
+    }
+
+    @Test
+    fun isLockscreenOrShadeVisibleAndInteractive_notVisible_false() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.isLockscreenOrShadeVisibleAndInteractive)
+            setWakefulness(WakefulnessState.AWAKE)
+
+            underTest.setIsLockscreenOrShadeVisible(false)
+
+            assertThat(actual).isFalse()
+        }
+
+    @Test
+    fun isLockscreenOrShadeVisibleAndInteractive_deviceAsleep_false() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.isLockscreenOrShadeVisibleAndInteractive)
+            underTest.setIsLockscreenOrShadeVisible(true)
+
+            setWakefulness(WakefulnessState.ASLEEP)
+
+            assertThat(actual).isFalse()
+        }
+
+    @Test
+    fun isLockscreenOrShadeVisibleAndInteractive_visibleAndAwake_true() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.isLockscreenOrShadeVisibleAndInteractive)
+
+            underTest.setIsLockscreenOrShadeVisible(true)
+            setWakefulness(WakefulnessState.AWAKE)
+
+            assertThat(actual).isTrue()
+        }
+
+    @Test
+    fun isLockscreenOrShadeVisibleAndInteractive_visibleAndStartingToWake_true() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.isLockscreenOrShadeVisibleAndInteractive)
+
+            underTest.setIsLockscreenOrShadeVisible(true)
+            setWakefulness(WakefulnessState.STARTING_TO_WAKE)
+
+            assertThat(actual).isTrue()
+        }
+
+    @Test
+    fun isLockscreenOrShadeVisibleAndInteractive_visibleAndStartingToSleep_true() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.isLockscreenOrShadeVisibleAndInteractive)
+
+            underTest.setIsLockscreenOrShadeVisible(true)
+            setWakefulness(WakefulnessState.STARTING_TO_SLEEP)
+
+            assertThat(actual).isTrue()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_statusBarServiceNotified() =
+        testScope.runTest {
+            underTest.start()
+
+            makeLockscreenShadeVisible()
+            testScope.runCurrent()
+            executor.runAllReady()
+
+            verify(iStatusBarService).onPanelRevealed(any(), any())
+        }
+
+    @Test
+    fun lockscreenShadeNotInteractive_statusBarServiceNotified() =
+        testScope.runTest {
+            underTest.start()
+
+            // First, make the shade visible
+            makeLockscreenShadeVisible()
+            testScope.runCurrent()
+            reset(iStatusBarService)
+
+            // WHEN lockscreen or shade is no longer visible
+            underTest.setIsLockscreenOrShadeVisible(false)
+            testScope.runCurrent()
+            executor.runAllReady()
+
+            // THEN status bar service is notified
+            verify(iStatusBarService).onPanelHidden()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_presenterCollapsed_notifEffectsNotCleared() =
+        testScope.runTest {
+            underTest.start()
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(true)
+
+            makeLockscreenShadeVisible()
+
+            val shouldClearNotifEffects = argumentCaptor<Boolean>()
+            verify(iStatusBarService).onPanelRevealed(shouldClearNotifEffects.capture(), any())
+            assertThat(shouldClearNotifEffects.value).isFalse()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_nullPresenter_notifEffectsNotCleared() =
+        testScope.runTest {
+            underTest.start()
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+
+            underTest.setUp(presenter = null, notificationsController)
+
+            makeLockscreenShadeVisible()
+
+            val shouldClearNotifEffects = argumentCaptor<Boolean>()
+            verify(iStatusBarService).onPanelRevealed(shouldClearNotifEffects.capture(), any())
+            assertThat(shouldClearNotifEffects.value).isFalse()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_stateKeyguard_notifEffectsNotCleared() =
+        testScope.runTest {
+            underTest.start()
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(false)
+
+            keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+
+            makeLockscreenShadeVisible()
+
+            val shouldClearNotifEffects = argumentCaptor<Boolean>()
+            verify(iStatusBarService).onPanelRevealed(shouldClearNotifEffects.capture(), any())
+            assertThat(shouldClearNotifEffects.value).isFalse()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_stateShade_presenterNotCollapsed_notifEffectsCleared() =
+        testScope.runTest {
+            underTest.start()
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(false)
+
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+
+            makeLockscreenShadeVisible()
+
+            val shouldClearNotifEffects = argumentCaptor<Boolean>()
+            verify(iStatusBarService).onPanelRevealed(shouldClearNotifEffects.capture(), any())
+            assertThat(shouldClearNotifEffects.value).isTrue()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_stateShadeLocked_presenterNotCollapsed_notifEffectsCleared() =
+        testScope.runTest {
+            underTest.start()
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(false)
+
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+
+            makeLockscreenShadeVisible()
+
+            val shouldClearNotifEffects = argumentCaptor<Boolean>()
+            verify(iStatusBarService).onPanelRevealed(shouldClearNotifEffects.capture(), any())
+            assertThat(shouldClearNotifEffects.value).isTrue()
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_hasHeadsUpAndNotifPresenterCollapsed_notifCountOne() =
+        testScope.runTest {
+            underTest.start()
+
+            whenever(headsUpManager.hasPinnedHeadsUp()).thenReturn(true)
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(true)
+            whenever(notificationsController.getActiveNotificationsCount()).thenReturn(4)
+
+            makeLockscreenShadeVisible()
+
+            val notifCount = argumentCaptor<Int>()
+            verify(iStatusBarService).onPanelRevealed(any(), notifCount.capture())
+            assertThat(notifCount.value).isEqualTo(1)
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_hasHeadsUpAndNullPresenter_notifCountOne() =
+        testScope.runTest {
+            underTest.start()
+
+            whenever(headsUpManager.hasPinnedHeadsUp()).thenReturn(true)
+            underTest.setUp(presenter = null, notificationsController)
+
+            makeLockscreenShadeVisible()
+
+            val notifCount = argumentCaptor<Int>()
+            verify(iStatusBarService).onPanelRevealed(any(), notifCount.capture())
+            assertThat(notifCount.value).isEqualTo(1)
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_noHeadsUp_notifCountMatchesNotifController() =
+        testScope.runTest {
+            underTest.start()
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(true)
+
+            whenever(headsUpManager.hasPinnedHeadsUp()).thenReturn(false)
+            whenever(notificationsController.getActiveNotificationsCount()).thenReturn(9)
+
+            makeLockscreenShadeVisible()
+
+            val notifCount = argumentCaptor<Int>()
+            verify(iStatusBarService).onPanelRevealed(any(), notifCount.capture())
+            assertThat(notifCount.value).isEqualTo(9)
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_notifPresenterNotCollapsed_notifCountMatchesNotifController() =
+        testScope.runTest {
+            underTest.start()
+            whenever(headsUpManager.hasPinnedHeadsUp()).thenReturn(true)
+
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(false)
+            whenever(notificationsController.getActiveNotificationsCount()).thenReturn(8)
+
+            makeLockscreenShadeVisible()
+
+            val notifCount = argumentCaptor<Int>()
+            verify(iStatusBarService).onPanelRevealed(any(), notifCount.capture())
+            assertThat(notifCount.value).isEqualTo(8)
+        }
+
+    @Test
+    fun lockscreenShadeInteractive_noHeadsUp_noNotifController_notifCountZero() =
+        testScope.runTest {
+            underTest.start()
+            whenever(notificationPresenter.isPresenterFullyCollapsed).thenReturn(true)
+
+            whenever(headsUpManager.hasPinnedHeadsUp()).thenReturn(false)
+            underTest.setUp(notificationPresenter, notificationsController = null)
+
+            makeLockscreenShadeVisible()
+
+            val notifCount = argumentCaptor<Int>()
+            verify(iStatusBarService).onPanelRevealed(any(), notifCount.capture())
+            assertThat(notifCount.value).isEqualTo(0)
+        }
+
+    private fun makeLockscreenShadeVisible() {
+        underTest.setIsLockscreenOrShadeVisible(true)
+        setWakefulness(WakefulnessState.AWAKE)
+        testScope.runCurrent()
+        executor.runAllReady()
+    }
+
+    private fun setWakefulness(state: WakefulnessState) {
+        val model = WakefulnessModel(state, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
+        keyguardRepository.setWakefulnessModel(model)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 951cadd..145629a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -22,6 +22,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.shared.model.WakeSleepReason
@@ -41,10 +42,12 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Assume.assumeTrue
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 
@@ -55,18 +58,20 @@
     private val utils = SceneTestUtils(this)
     private val testScope = utils.testScope
     private val sceneInteractor = utils.sceneInteractor()
-    private val featureFlags = utils.featureFlags
+    private val sceneContainerFlags = utils.sceneContainerFlags
     private val authenticationRepository = utils.authenticationRepository()
     private val authenticationInteractor =
         utils.authenticationInteractor(
             repository = authenticationRepository,
+            sceneInteractor = sceneInteractor,
         )
-    private val keyguardRepository = utils.keyguardRepository()
+    private val keyguardRepository = utils.keyguardRepository
     private val keyguardInteractor =
         utils.keyguardInteractor(
             repository = keyguardRepository,
         )
     private val sysUiState: SysUiState = mock()
+    private val falsingCollector: FalsingCollector = mock()
 
     private val underTest =
         SceneContainerStartable(
@@ -74,10 +79,11 @@
             sceneInteractor = sceneInteractor,
             authenticationInteractor = authenticationInteractor,
             keyguardInteractor = keyguardInteractor,
-            featureFlags = featureFlags,
+            flags = sceneContainerFlags,
             sysUiState = sysUiState,
             displayId = Display.DEFAULT_DISPLAY,
             sceneLogger = mock(),
+            falsingCollector = falsingCollector,
         )
 
     @Test
@@ -243,7 +249,7 @@
             assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
             underTest.start()
 
-            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
 
             assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
         }
@@ -259,7 +265,7 @@
             assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
             underTest.start()
 
-            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
 
             assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
         }
@@ -275,7 +281,7 @@
             assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
             underTest.start()
 
-            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
 
             assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
         }
@@ -294,18 +300,225 @@
 
             authenticationRepository.setUnlocked(true)
             runCurrent()
-            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE)
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
 
             assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
         }
 
+    @Test
+    fun collectFalsingSignals_onSuccessfulUnlock() =
+        testScope.runTest {
+            prepareState(
+                initialSceneKey = SceneKey.Lockscreen,
+                authenticationMethod = AuthenticationMethodModel.Pin,
+                isDeviceUnlocked = false,
+            )
+            underTest.start()
+            runCurrent()
+            verify(falsingCollector, never()).onSuccessfulUnlock()
+
+            // Move around scenes without unlocking.
+            listOf(
+                    SceneKey.Shade,
+                    SceneKey.QuickSettings,
+                    SceneKey.Shade,
+                    SceneKey.Lockscreen,
+                    SceneKey.Bouncer,
+                )
+                .forEach { sceneKey ->
+                    sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
+                    runCurrent()
+                    verify(falsingCollector, never()).onSuccessfulUnlock()
+                }
+
+            // Changing to the Gone scene should report a successful unlock.
+            sceneInteractor.changeScene(SceneModel(SceneKey.Gone), "reason")
+            runCurrent()
+            verify(falsingCollector).onSuccessfulUnlock()
+
+            // Move around scenes without changing back to Lockscreen, shouldn't report another
+            // unlock.
+            listOf(
+                    SceneKey.Shade,
+                    SceneKey.QuickSettings,
+                    SceneKey.Shade,
+                    SceneKey.Gone,
+                )
+                .forEach { sceneKey ->
+                    sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
+                    runCurrent()
+                    verify(falsingCollector, times(1)).onSuccessfulUnlock()
+                }
+
+            // Changing to the Lockscreen scene shouldn't report a successful unlock.
+            sceneInteractor.changeScene(SceneModel(SceneKey.Lockscreen), "reason")
+            runCurrent()
+            verify(falsingCollector, times(1)).onSuccessfulUnlock()
+
+            // Move around scenes without unlocking.
+            listOf(
+                    SceneKey.Shade,
+                    SceneKey.QuickSettings,
+                    SceneKey.Shade,
+                    SceneKey.Lockscreen,
+                    SceneKey.Bouncer,
+                )
+                .forEach { sceneKey ->
+                    sceneInteractor.changeScene(SceneModel(sceneKey), "reason")
+                    runCurrent()
+                    verify(falsingCollector, times(1)).onSuccessfulUnlock()
+                }
+
+            // Changing to the Gone scene should report a second successful unlock.
+            sceneInteractor.changeScene(SceneModel(SceneKey.Gone), "reason")
+            runCurrent()
+            verify(falsingCollector, times(2)).onSuccessfulUnlock()
+        }
+
+    @Test
+    fun collectFalsingSignals_setShowingAod() =
+        testScope.runTest {
+            prepareState(
+                initialSceneKey = SceneKey.Lockscreen,
+                authenticationMethod = AuthenticationMethodModel.Pin,
+                isDeviceUnlocked = false,
+            )
+            underTest.start()
+            runCurrent()
+            verify(falsingCollector).setShowingAod(false)
+
+            keyguardRepository.setIsDozing(true)
+            runCurrent()
+            verify(falsingCollector).setShowingAod(true)
+
+            keyguardRepository.setIsDozing(false)
+            runCurrent()
+            verify(falsingCollector, times(2)).setShowingAod(false)
+        }
+
+    @Test
+    fun collectFalsingSignals_screenOnAndOff_aodUnavailable() =
+        testScope.runTest {
+            keyguardRepository.setAodAvailable(false)
+            runCurrent()
+            prepareState(
+                initialSceneKey = SceneKey.Lockscreen,
+                authenticationMethod = AuthenticationMethodModel.Pin,
+                isDeviceUnlocked = false,
+            )
+            underTest.start()
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+            runCurrent()
+            verify(falsingCollector, times(1)).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(ASLEEP)
+            runCurrent()
+            verify(falsingCollector, times(1)).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, times(1)).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_TAP)
+            runCurrent()
+            verify(falsingCollector, times(1)).onScreenTurningOn()
+            verify(falsingCollector, times(1)).onScreenOnFromTouch()
+            verify(falsingCollector, times(1)).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(ASLEEP)
+            runCurrent()
+            verify(falsingCollector, times(1)).onScreenTurningOn()
+            verify(falsingCollector, times(1)).onScreenOnFromTouch()
+            verify(falsingCollector, times(2)).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+            runCurrent()
+            verify(falsingCollector, times(2)).onScreenTurningOn()
+            verify(falsingCollector, times(1)).onScreenOnFromTouch()
+            verify(falsingCollector, times(2)).onScreenOff()
+        }
+
+    @Test
+    fun collectFalsingSignals_screenOnAndOff_aodAvailable() =
+        testScope.runTest {
+            keyguardRepository.setAodAvailable(true)
+            runCurrent()
+            prepareState(
+                initialSceneKey = SceneKey.Lockscreen,
+                authenticationMethod = AuthenticationMethodModel.Pin,
+                isDeviceUnlocked = false,
+            )
+            underTest.start()
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(ASLEEP)
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_TAP)
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(ASLEEP)
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+
+            keyguardRepository.setWakefulnessModel(STARTING_TO_WAKE_FROM_POWER_BUTTON)
+            runCurrent()
+            verify(falsingCollector, never()).onScreenTurningOn()
+            verify(falsingCollector, never()).onScreenOnFromTouch()
+            verify(falsingCollector, never()).onScreenOff()
+        }
+
+    @Test
+    fun collectFalsingSignals_bouncerVisibility() =
+        testScope.runTest {
+            prepareState(
+                initialSceneKey = SceneKey.Lockscreen,
+                authenticationMethod = AuthenticationMethodModel.Pin,
+                isDeviceUnlocked = false,
+            )
+            underTest.start()
+            runCurrent()
+            verify(falsingCollector).onBouncerHidden()
+
+            sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+            runCurrent()
+            verify(falsingCollector).onBouncerShown()
+
+            sceneInteractor.changeScene(SceneModel(SceneKey.Gone), "reason")
+            runCurrent()
+            verify(falsingCollector, times(2)).onBouncerHidden()
+        }
+
     private fun prepareState(
         isDeviceUnlocked: Boolean = false,
         isBypassEnabled: Boolean = false,
         initialSceneKey: SceneKey? = null,
         authenticationMethod: AuthenticationMethodModel? = null,
     ): MutableStateFlow<ObservableTransitionState> {
-        featureFlags.set(Flags.SCENE_CONTAINER, true)
+        assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
+        sceneContainerFlags.enabled = true
         authenticationRepository.setUnlocked(isDeviceUnlocked)
         keyguardRepository.setBypassEnabled(isBypassEnabled)
         val transitionStateFlow =
@@ -334,11 +547,23 @@
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
                 lastSleepReason = WakeSleepReason.POWER_BUTTON
             )
-        private val STARTING_TO_WAKE =
+        private val ASLEEP =
+            WakefulnessModel(
+                state = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.POWER_BUTTON
+            )
+        private val STARTING_TO_WAKE_FROM_POWER_BUTTON =
             WakefulnessModel(
                 state = WakefulnessState.STARTING_TO_WAKE,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
                 lastSleepReason = WakeSleepReason.POWER_BUTTON
             )
+        private val STARTING_TO_WAKE_FROM_TAP =
+            WakefulnessModel(
+                state = WakefulnessState.STARTING_TO_WAKE,
+                lastWakeReason = WakeSleepReason.TAP,
+                lastSleepReason = WakeSleepReason.POWER_BUTTON
+            )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
new file mode 100644
index 0000000..17ee3a1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/shared/flag/SceneContainerFlagsTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.shared.flag
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ReleasedFlag
+import com.android.systemui.flags.ResourceBooleanFlag
+import com.android.systemui.flags.UnreleasedFlag
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@SmallTest
+@RunWith(Parameterized::class)
+internal class SceneContainerFlagsTest(
+    private val testCase: TestCase,
+) : SysuiTestCase() {
+
+    private lateinit var underTest: SceneContainerFlags
+
+    @Before
+    fun setUp() {
+        val featureFlags =
+            FakeFeatureFlagsClassic().apply {
+                SceneContainerFlagsImpl.flags.forEach { flag ->
+                    when (flag) {
+                        is ResourceBooleanFlag -> set(flag, testCase.areAllFlagsSet)
+                        is ReleasedFlag -> set(flag, testCase.areAllFlagsSet)
+                        is UnreleasedFlag -> set(flag, testCase.areAllFlagsSet)
+                        else -> error("Unsupported flag type ${flag.javaClass}")
+                    }
+                }
+            }
+        underTest = SceneContainerFlagsImpl(featureFlags, testCase.isComposeAvailable)
+    }
+
+    @Test
+    fun isEnabled() {
+        assumeTrue(Flags.SCENE_CONTAINER_ENABLED)
+        assertThat(underTest.isEnabled()).isEqualTo(testCase.expectedEnabled)
+    }
+
+    internal data class TestCase(
+        val isComposeAvailable: Boolean,
+        val areAllFlagsSet: Boolean,
+        val expectedEnabled: Boolean,
+    ) {
+        override fun toString(): String {
+            return """
+                (compose=$isComposeAvailable + flags=$areAllFlagsSet) -> expected=$expectedEnabled
+            """
+                .trimIndent()
+        }
+    }
+
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun testCases() = buildList {
+            repeat(4) { combination ->
+                val isComposeAvailable = combination and 0b100 != 0
+                val areAllFlagsSet = combination and 0b001 != 0
+
+                val expectedEnabled = isComposeAvailable && areAllFlagsSet
+
+                add(
+                    TestCase(
+                        isComposeAvailable = isComposeAvailable,
+                        areAllFlagsSet = areAllFlagsSet,
+                        expectedEnabled = expectedEnabled,
+                    )
+                )
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 88abb642..0b56a59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -39,7 +39,8 @@
     private val interactor = utils.sceneInteractor()
     private val underTest =
         SceneContainerViewModel(
-            interactor = interactor,
+            sceneInteractor = interactor,
+            falsingInteractor = utils.falsingInteractor(),
         )
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
index ee61f57..587da2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
@@ -140,7 +140,7 @@
     private val pipTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_PINNED
-            bounds = Rect(628, 1885, 1038, 2295)
+            setBounds(Rect(628, 1885, 1038, 2295))
             activityType = ACTIVITY_TYPE_STANDARD
         }
         displayId = DISPLAY_ID
@@ -164,7 +164,7 @@
     private val fullScreenWorkProfileTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_FULLSCREEN
-            bounds = Rect(0, 0, 1080, 2400)
+            setBounds(Rect(0, 0, 1080, 2400))
             activityType = ACTIVITY_TYPE_STANDARD
         }
         displayId = DISPLAY_ID
@@ -188,7 +188,7 @@
     private val launcherTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_FULLSCREEN
-            bounds = Rect(0, 0, 1080, 2400)
+            setBounds(Rect(0, 0, 1080, 2400))
             activityType = ACTIVITY_TYPE_HOME
         }
         displayId = DISPLAY_ID
@@ -212,7 +212,7 @@
     private val emptyTask = RootTaskInfo().apply {
         configuration.windowConfiguration.apply {
             windowingMode = WINDOWING_MODE_FULLSCREEN
-            bounds = Rect(0, 0, 1080, 2400)
+            setBounds(Rect(0, 0, 1080, 2400))
             activityType = ACTIVITY_TYPE_UNDEFINED
         }
         displayId = DISPLAY_ID
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 209dcc1d..1c9ec27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -626,6 +626,7 @@
                 mScreenOffAnimationController,
                 mLockscreenGestureLogger,
                 mShadeExpansionStateManager,
+                mShadeRepository,
                 mSysUIUnfoldComponent,
                 mSysUiState,
                 () -> mKeyguardBottomAreaViewController,
@@ -716,7 +717,6 @@
                 mAmbientState,
                 mRecordingController,
                 mFalsingManager,
-                new FalsingCollectorFake(),
                 mAccessibilityManager,
                 mLockscreenGestureLogger,
                 mMetricsLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 1738b06..dfd782b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -63,6 +63,8 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import com.google.common.util.concurrent.MoreExecutors;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -73,6 +75,7 @@
 import org.mockito.Spy;
 
 import java.util.List;
+import java.util.concurrent.Executor;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -98,6 +101,7 @@
     @Mock private ShadeWindowLogger mShadeWindowLogger;
     @Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters;
     @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener;
+    private final Executor mBackgroundExecutor = MoreExecutors.directExecutor();
 
     private NotificationShadeWindowControllerImpl mNotificationShadeWindowController;
     private float mPreferredRefreshRate = -1;
@@ -125,6 +129,7 @@
                 mConfigurationController,
                 mKeyguardViewMediator,
                 mKeyguardBypassController,
+                mBackgroundExecutor,
                 mColorExtractor,
                 mDumpManager,
                 mKeyguardStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 3cce423..39fe498 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.dock.DockManager
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
@@ -56,6 +57,8 @@
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.DozeScrimController
+import com.android.systemui.statusbar.phone.DozeServiceHost
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
@@ -90,6 +93,8 @@
     @Mock private lateinit var view: NotificationShadeWindowView
     @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
     @Mock private lateinit var centralSurfaces: CentralSurfaces
+    @Mock private lateinit var dozeServiceHost: DozeServiceHost
+    @Mock private lateinit var dozeScrimController: DozeScrimController
     @Mock private lateinit var backActionInteractor: BackActionInteractor
     @Mock private lateinit var powerInteractor: PowerInteractor
     @Mock private lateinit var dockManager: DockManager
@@ -98,6 +103,7 @@
     @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
     @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
     @Mock private lateinit var shadeLogger: ShadeLogger
+    @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var ambientState: AmbientState
     @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel
     @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController
@@ -155,46 +161,49 @@
         fakeClock = FakeSystemClock()
         underTest =
             NotificationShadeWindowViewController(
-                    lockscreenShadeTransitionController,
-                    FalsingCollectorFake(),
-                    sysuiStatusBarStateController,
-                    dockManager,
-                    notificationShadeDepthController,
-                    view,
-                    notificationPanelViewController,
-                    ShadeExpansionStateManager(),
-                    stackScrollLayoutController,
-                    statusBarKeyguardViewManager,
-                    statusBarWindowStateController,
-                    lockIconViewController,
-                    centralSurfaces,
-                    backActionInteractor,
-                    powerInteractor,
-                    notificationShadeWindowController,
-                    unfoldTransitionProgressProvider,
-                    keyguardUnlockAnimationController,
-                    notificationInsetsController,
-                    ambientState,
-                    shadeLogger,
-                    pulsingGestureListener,
-                    mLockscreenHostedDreamGestureListener,
-                    keyguardBouncerViewModel,
-                    keyguardBouncerComponentFactory,
-                    mock(KeyguardMessageAreaController.Factory::class.java),
-                    keyguardTransitionInteractor,
-                    primaryBouncerToGoneTransitionViewModel,
-                    notificationExpansionRepository,
-                    featureFlags,
-                    fakeClock,
-                    BouncerMessageInteractor(
-                        FakeBouncerMessageRepository(),
-                        mock(BouncerMessageFactory::class.java),
-                        FakeUserRepository(),
-                        CountDownTimerUtil(),
-                        featureFlags
-                    ),
-                    BouncerLogger(logcatLogBuffer("BouncerLog")),
-                    keyEventInteractor,
+                lockscreenShadeTransitionController,
+                FalsingCollectorFake(),
+                sysuiStatusBarStateController,
+                dockManager,
+                notificationShadeDepthController,
+                view,
+                notificationPanelViewController,
+                ShadeExpansionStateManager(),
+                stackScrollLayoutController,
+                statusBarKeyguardViewManager,
+                statusBarWindowStateController,
+                lockIconViewController,
+                centralSurfaces,
+                dozeServiceHost,
+                dozeScrimController,
+                backActionInteractor,
+                powerInteractor,
+                notificationShadeWindowController,
+                unfoldTransitionProgressProvider,
+                keyguardUnlockAnimationController,
+                notificationInsetsController,
+                ambientState,
+                shadeLogger,
+                dumpManager,
+                pulsingGestureListener,
+                mLockscreenHostedDreamGestureListener,
+                keyguardBouncerViewModel,
+                keyguardBouncerComponentFactory,
+                mock(KeyguardMessageAreaController.Factory::class.java),
+                keyguardTransitionInteractor,
+                primaryBouncerToGoneTransitionViewModel,
+                notificationExpansionRepository,
+                featureFlags,
+                fakeClock,
+                BouncerMessageInteractor(
+                    FakeBouncerMessageRepository(),
+                    mock(BouncerMessageFactory::class.java),
+                    FakeUserRepository(),
+                    CountDownTimerUtil(),
+                    featureFlags
+                ),
+                BouncerLogger(logcatLogBuffer("BouncerLog")),
+                keyEventInteractor,
             )
         underTest.setupExpandedStatusBar()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 66d48d6..3031658 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.dock.DockManager
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
@@ -56,6 +57,8 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.DozeScrimController
+import com.android.systemui.statusbar.phone.DozeServiceHost
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
@@ -89,6 +92,8 @@
     @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
     @Mock private lateinit var shadeController: ShadeController
     @Mock private lateinit var centralSurfaces: CentralSurfaces
+    @Mock private lateinit var dozeServiceHost: DozeServiceHost
+    @Mock private lateinit var dozeScrimController: DozeScrimController
     @Mock private lateinit var backActionInteractor: BackActionInteractor
     @Mock private lateinit var powerInteractor: PowerInteractor
     @Mock private lateinit var dockManager: DockManager
@@ -107,6 +112,7 @@
     @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
     @Mock private lateinit var ambientState: AmbientState
     @Mock private lateinit var shadeLogger: ShadeLogger
+    @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
     @Mock
     private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener
@@ -174,6 +180,8 @@
                 statusBarWindowStateController,
                 lockIconViewController,
                 centralSurfaces,
+                dozeServiceHost,
+                dozeScrimController,
                 backActionInteractor,
                 powerInteractor,
                 notificationShadeWindowController,
@@ -182,6 +190,7 @@
                 notificationInsetsController,
                 ambientState,
                 shadeLogger,
+                dumpManager,
                 pulsingGestureListener,
                 mLockscreenHostedDreamGestureListener,
                 keyguardBouncerViewModel,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index e22e571..e42a7a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -37,7 +37,7 @@
 import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentHostManager;
@@ -62,6 +62,7 @@
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
@@ -132,7 +133,6 @@
     @Mock protected AmbientState mAmbientState;
     @Mock protected RecordingController mRecordingController;
     @Mock protected FalsingManager mFalsingManager;
-    @Mock protected FalsingCollector mFalsingCollector;
     @Mock protected AccessibilityManager mAccessibilityManager;
     @Mock protected LockscreenGestureLogger mLockscreenGestureLogger;
     @Mock protected MetricsLogger mMetricsLogger;
@@ -176,6 +176,9 @@
                         new FakeUserSetupRepository(),
                         mDeviceProvisionedController,
                         mUserInteractor,
+                        new SharedNotificationContainerInteractor(
+                                new FakeConfigurationRepository(),
+                                mContext),
                         mShadeRepository
                 );
 
@@ -242,7 +245,6 @@
                 mAmbientState,
                 mRecordingController,
                 mFalsingManager,
-                mFalsingCollector,
                 mAccessibilityManager,
                 mLockscreenGestureLogger,
                 mMetricsLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 6a14a00..bf2d6a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -20,20 +20,28 @@
 import android.view.Display
 import android.view.WindowManager
 import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.IStatusBarService
+import com.android.keyguard.TestScopeProvider
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.assist.AssistManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
 import dagger.Lazy
 import org.junit.Before
 import org.junit.Test
@@ -47,6 +55,8 @@
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
 class ShadeControllerImplTest : SysuiTestCase() {
+    private val executor = FakeExecutor(FakeSystemClock())
+
     @Mock private lateinit var commandQueue: CommandQueue
     @Mock private lateinit var keyguardStateController: KeyguardStateController
     @Mock private lateinit var statusBarStateController: StatusBarStateController
@@ -61,6 +71,17 @@
     @Mock private lateinit var nswvc: NotificationShadeWindowViewController
     @Mock private lateinit var display: Display
     @Mock private lateinit var touchLog: LogBuffer
+    @Mock private lateinit var iStatusBarService: IStatusBarService
+    @Mock private lateinit var headsUpManager: HeadsUpManager
+
+    private val windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor by lazy {
+        WindowRootViewVisibilityInteractor(
+            TestScopeProvider.getTestScope(),
+            WindowRootViewVisibilityRepository(iStatusBarService, executor),
+            FakeKeyguardRepository(),
+            headsUpManager,
+        )
+    }
 
     private lateinit var shadeController: ShadeControllerImpl
 
@@ -74,6 +95,7 @@
                 commandQueue,
                 FakeExecutor(FakeSystemClock()),
                 touchLog,
+                windowRootViewVisibilityInteractor,
                 keyguardStateController,
                 statusBarStateController,
                 statusBarKeyguardViewManager,
@@ -86,6 +108,7 @@
                 Lazy { gutsManager },
             )
         shadeController.setNotificationShadeWindowViewController(nswvc)
+        shadeController.setVisibilityListener(mock())
     }
 
     @Test
@@ -133,4 +156,24 @@
         // VERIFY that cancelCurrentTouch is NOT called
         verify(nswvc, never()).cancelCurrentTouch()
     }
+
+    @Test
+    fun visible_changesToTrue_windowInteractorUpdated() {
+        shadeController.makeExpandedVisible(true)
+
+        assertThat(windowRootViewVisibilityInteractor.isLockscreenOrShadeVisible.value).isTrue()
+    }
+
+    @Test
+    fun visible_changesToFalse_windowInteractorUpdated() {
+        // GIVEN the shade is currently expanded
+        shadeController.makeExpandedVisible(true)
+        assertThat(windowRootViewVisibilityInteractor.isLockscreenOrShadeVisible.value).isTrue()
+
+        // WHEN the shade is collapsed
+        shadeController.collapseShade()
+
+        // THEN the interactor is notified
+        assertThat(windowRootViewVisibilityInteractor.isLockscreenOrShadeVisible.value).isFalse()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 5fa6b3a..e7056c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -58,6 +58,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
 import com.android.systemui.util.CarrierConfigTracker;
+import com.android.systemui.util.kotlin.FlowProviderKt;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 import com.android.systemui.utils.os.FakeHandler;
 
@@ -72,6 +73,8 @@
 import java.util.Arrays;
 import java.util.List;
 
+import kotlinx.coroutines.flow.MutableStateFlow;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -105,7 +108,8 @@
     private ShadeCarrier mShadeCarrier3;
     private TestableLooper mTestableLooper;
     @Mock
-    private ShadeCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+    private ShadeCarrierGroupController.OnSingleCarrierChangedListener
+            mOnSingleCarrierChangedListener;
     @Mock
     private MobileUiAdapter mMobileUiAdapter;
     @Mock
@@ -119,6 +123,9 @@
     @Mock
     private StatusBarPipelineFlags mStatusBarPipelineFlags;
 
+    private final MutableStateFlow<Boolean> mIsVisibleFlow =
+            FlowProviderKt.getMutableStateFlow(true);
+
     private FakeSlotIndexResolver mSlotIndexResolver;
     private ClickListenerTextView mNoCarrierTextView;
 
@@ -170,7 +177,7 @@
                 mMobileUiAdapter,
                 mMobileContextProvider,
                 mStatusBarPipelineFlags
-            )
+        )
                 .setShadeCarrierGroup(mShadeCarrierGroup)
                 .build();
 
@@ -181,6 +188,7 @@
         when(mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()).thenReturn(true);
         when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
         when(mMobileIconsViewModel.getLogger()).thenReturn(mMobileViewLogger);
+        when(mShadeCarrierGroupMobileIconViewModel.isVisible()).thenReturn(mIsVisibleFlow);
         when(mMobileIconsViewModel.viewModelForSub(anyInt(), any()))
                 .thenReturn(mShadeCarrierGroupMobileIconViewModel);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index e6e7482..41ea5b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -25,7 +25,9 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
@@ -36,6 +38,7 @@
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
@@ -52,6 +55,7 @@
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -71,6 +75,12 @@
     private val disableFlagsRepository = FakeDisableFlagsRepository()
     private val keyguardRepository = FakeKeyguardRepository()
     private val shadeRepository = FakeShadeRepository()
+    private val configurationRepository = FakeConfigurationRepository()
+    private val sharedNotificationContainerInteractor =
+        SharedNotificationContainerInteractor(
+            configurationRepository,
+            mContext,
+        )
 
     @Mock private lateinit var manager: UserManager
     @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@@ -145,6 +155,7 @@
                 userSetupRepository,
                 deviceProvisionedController,
                 userInteractor,
+                sharedNotificationContainerInteractor,
                 shadeRepository,
             )
     }
@@ -363,7 +374,7 @@
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
-            shadeRepository.setShadeExpansion(0.5f)
+            shadeRepository.setLockscreenShadeExpansion(0.5f)
 
             assertThat(actual).isEqualTo(1f)
         }
@@ -375,10 +386,52 @@
 
             keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
 
-            shadeRepository.setShadeExpansion(0.5f)
+            shadeRepository.setLockscreenShadeExpansion(0.5f)
             assertThat(actual).isEqualTo(0.5f)
 
-            shadeRepository.setShadeExpansion(0.8f)
+            shadeRepository.setLockscreenShadeExpansion(0.8f)
             assertThat(actual).isEqualTo(0.8f)
         }
+
+    fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            // WHEN split shade is enabled and QS is expanded
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            configurationRepository.onAnyConfigurationChange()
+            runCurrent()
+            shadeRepository.setQsExpansion(.5f)
+            shadeRepository.setLegacyShadeExpansion(.7f)
+
+            // THEN legacy shade expansion is passed through
+            assertThat(actual).isEqualTo(.7f)
+        }
+
+    fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            // WHEN split shade is not enabled and QS is expanded
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            shadeRepository.setQsExpansion(.5f)
+            shadeRepository.setLegacyShadeExpansion(1f)
+
+            // THEN shade expansion is zero
+            assertThat(actual).isEqualTo(0f)
+        }
+
+    fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            // WHEN split shade is not enabled and QS is expanded
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            shadeRepository.setQsExpansion(0f)
+            shadeRepository.setLegacyShadeExpansion(.6f)
+
+            // THEN shade expansion is zero
+            assertThat(actual).isEqualTo(.6f)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index fdaea22..e086712 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -121,18 +121,33 @@
         }
 
     @Test
-    fun updateShadeExpansion() =
+    fun updateDragDownAmount() =
         testScope.runTest {
-            assertThat(underTest.shadeExpansion.value).isEqualTo(0f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(0f)
 
-            underTest.setShadeExpansion(.5f)
-            assertThat(underTest.shadeExpansion.value).isEqualTo(.5f)
+            underTest.setLockscreenShadeExpansion(.5f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(.5f)
 
-            underTest.setShadeExpansion(.82f)
-            assertThat(underTest.shadeExpansion.value).isEqualTo(.82f)
+            underTest.setLockscreenShadeExpansion(.82f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(.82f)
 
-            underTest.setShadeExpansion(1f)
-            assertThat(underTest.shadeExpansion.value).isEqualTo(1f)
+            underTest.setLockscreenShadeExpansion(1f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(1f)
+        }
+
+    @Test
+    fun updateLegacyShadeExpansion() =
+        testScope.runTest {
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(0f)
+
+            underTest.setLegacyShadeExpansion(.5f)
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(.5f)
+
+            underTest.setLegacyShadeExpansion(.82f)
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(.82f)
+
+            underTest.setLegacyShadeExpansion(1f)
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(1f)
         }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
new file mode 100644
index 0000000..a09e844
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -0,0 +1,155 @@
+package com.android.systemui.shade.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class ShadeHeaderViewModelTest : SysuiTestCase() {
+    private val utils = SceneTestUtils(this)
+    private val testScope = utils.testScope
+    private val sceneInteractor = utils.sceneInteractor()
+
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
+                ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
+        )
+
+    private lateinit var underTest: ShadeHeaderViewModel
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        underTest =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+    }
+
+    @Test
+    fun isTransitioning_idle_false() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Shade))
+            )
+
+            assertThat(isTransitioning).isFalse()
+        }
+
+    @Test
+    fun isTransitioning_shadeToQs_true() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Shade,
+                        toScene = SceneKey.QuickSettings,
+                        progress = MutableStateFlow(0.5f)
+                    )
+                )
+            )
+
+            assertThat(isTransitioning).isTrue()
+        }
+
+    @Test
+    fun isTransitioning_qsToShade_true() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.QuickSettings,
+                        toScene = SceneKey.Shade,
+                        progress = MutableStateFlow(0.5f)
+                    )
+                )
+            )
+
+            assertThat(isTransitioning).isTrue()
+        }
+
+    @Test
+    fun isTransitioning_otherTransition_false() =
+        testScope.runTest {
+            val isTransitioning by collectLastValue(underTest.isTransitioning)
+            sceneInteractor.setTransitionState(
+                MutableStateFlow(
+                    ObservableTransitionState.Transition(
+                        fromScene = SceneKey.Gone,
+                        toScene = SceneKey.Shade,
+                        progress = MutableStateFlow(0.5f)
+                    )
+                )
+            )
+
+            assertThat(isTransitioning).isFalse()
+        }
+
+    @Test
+    fun mobileSubIds_update() =
+        testScope.runTest {
+            val mobileSubIds by collectLastValue(underTest.mobileSubIds)
+            mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1)
+
+            assertThat(mobileSubIds).isEqualTo(listOf(1))
+
+            mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
+
+            assertThat(mobileSubIds).isEqualTo(listOf(1, 2))
+        }
+
+    companion object {
+        private val SUB_1 =
+            SubscriptionModel(
+                subscriptionId = 1,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+            )
+        private val SUB_2 =
+            SubscriptionModel(
+                subscriptionId = 2,
+                isOpportunistic = false,
+                carrierName = "Carrier 2",
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 69b9525..5c75d9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -23,10 +23,18 @@
 import com.android.systemui.scene.SceneTestUtils
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.mockito.mock
 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.junit.runners.JUnit4
@@ -45,17 +53,51 @@
             sceneInteractor = sceneInteractor,
         )
 
-    private val underTest =
-        ShadeSceneViewModel(
-            applicationScope = testScope.backgroundScope,
-            authenticationInteractor = authenticationInteractor,
-            bouncerInteractor =
-                utils.bouncerInteractor(
-                    authenticationInteractor = authenticationInteractor,
-                    sceneInteractor = sceneInteractor,
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
+
+    private var mobileIconsViewModel: MobileIconsViewModel =
+        MobileIconsViewModel(
+            logger = mock(),
+            verboseLogger = mock(),
+            interactor = mobileIconsInteractor,
+            airplaneModeInteractor =
+                AirplaneModeInteractor(
+                    FakeAirplaneModeRepository(),
+                    FakeConnectivityRepository(),
                 ),
+            constants = mock(),
+            scope = testScope.backgroundScope,
         )
 
+    private lateinit var shadeHeaderViewModel: ShadeHeaderViewModel
+
+    private lateinit var underTest: ShadeSceneViewModel
+
+    @Before
+    fun setUp() {
+        shadeHeaderViewModel =
+            ShadeHeaderViewModel(
+                applicationScope = testScope.backgroundScope,
+                context = context,
+                sceneInteractor = sceneInteractor,
+                mobileIconsInteractor = mobileIconsInteractor,
+                mobileIconsViewModel = mobileIconsViewModel,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+
+        underTest =
+            ShadeSceneViewModel(
+                applicationScope = testScope.backgroundScope,
+                authenticationInteractor = authenticationInteractor,
+                bouncerInteractor =
+                    utils.bouncerInteractor(
+                        authenticationInteractor = authenticationInteractor,
+                        sceneInteractor = sceneInteractor,
+                    ),
+                shadeHeaderViewModel = shadeHeaderViewModel,
+            )
+    }
+
     @Test
     fun upTransitionSceneKey_deviceLocked_lockScreen() =
         testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 51e72c6..6f75880 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -10,6 +10,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -29,6 +30,7 @@
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
@@ -102,6 +104,11 @@
     @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
     private val disableFlagsRepository = FakeDisableFlagsRepository()
     private val keyguardRepository = FakeKeyguardRepository()
+    private val configurationRepository = FakeConfigurationRepository()
+    private val sharedNotificationContainerInteractor = SharedNotificationContainerInteractor(
+        configurationRepository,
+        mContext,
+    )
     private val shadeInteractor =
         ShadeInteractor(
             testScope.backgroundScope,
@@ -110,6 +117,7 @@
             userSetupRepository = FakeUserSetupRepository(),
             deviceProvisionedController = mock(),
             userInteractor = mock(),
+            sharedNotificationContainerInteractor,
             repository = FakeShadeRepository(),
         )
     private val powerInteractor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
index 786856b..66d2465 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State.CONNECTED
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.privacy.PrivacyItemController
@@ -105,5 +106,7 @@
         suspend fun emit(value: ConnectedDisplayInteractor.State) = flow.emit(value)
         override val connectedDisplayState: Flow<ConnectedDisplayInteractor.State>
             get() = flow
+        override val pendingDisplay: Flow<PendingDisplay?>
+            get() = MutableSharedFlow<PendingDisplay>()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index 6be2fa5..4fcccf8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -93,9 +93,6 @@
                 fakeFeatureFlags
             )
 
-        // ensure that isTooEarly() check in SystemStatusAnimationScheduler does not return true
-        systemClock.advanceTime(Process.getStartUptimeMillis() + MIN_UPTIME)
-
         // StatusBarContentInsetProvider is mocked. Ensure that it returns some mocked values.
         whenever(statusBarContentInsetProvider.getStatusBarContentInsetsForCurrentRotation())
             .thenReturn(android.util.Pair(10, 10))
@@ -156,6 +153,21 @@
         assertEquals(0f, batteryChip.view.alpha)
     }
 
+    /** Regression test for b/294104969. */
+    @Test
+    fun testPrivacyStatusEvent_beforeSystemUptime_stillDisplayed() = runTest {
+        initializeSystemStatusAnimationScheduler(testScope = this, advancePastMinUptime = false)
+
+        // WHEN the uptime hasn't quite passed the minimum required uptime...
+        systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME / 2)
+
+        // BUT the event is a privacy event
+        createAndScheduleFakePrivacyEvent()
+
+        // THEN the privacy event still happens
+        assertEquals(ANIMATION_QUEUED, systemStatusAnimationScheduler.getAnimationState())
+    }
+
     @Test
     fun testPrivacyStatusEvent_standardAnimationLifecycle() = runTest {
         // Instantiate class under test with TestScope from runTest
@@ -568,7 +580,10 @@
         return batteryChip
     }
 
-    private fun initializeSystemStatusAnimationScheduler(testScope: TestScope) {
+    private fun initializeSystemStatusAnimationScheduler(
+        testScope: TestScope,
+        advancePastMinUptime: Boolean = true,
+    ) {
         systemStatusAnimationScheduler =
             SystemStatusAnimationSchedulerImpl(
                 systemEventCoordinator,
@@ -581,5 +596,10 @@
             )
         // add a mock listener
         systemStatusAnimationScheduler.addCallback(listener)
+
+        if (advancePastMinUptime) {
+            // ensure that isTooEarly() check in SystemStatusAnimationScheduler does not return true
+            systemClock.advanceTime(Process.getStartUptimeMillis() + MIN_UPTIME)
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index 55ea3157..65697b73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -24,6 +24,7 @@
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -77,13 +78,18 @@
 
     private lateinit var coordinator: ConversationCoordinator
 
+    private val featureFlags = FakeFeatureFlagsClassic()
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         coordinator = ConversationCoordinator(
             peopleNotificationIdentifier,
             conversationIconManager,
-            HighPriorityProvider(peopleNotificationIdentifier, GroupMembershipManagerImpl()),
+            HighPriorityProvider(
+                peopleNotificationIdentifier,
+                GroupMembershipManagerImpl(featureFlags)
+            ),
             headerController
         )
         whenever(channel.isImportantConversation).thenReturn(true)
@@ -182,7 +188,7 @@
     }
 
     @Test
-    fun testInAlertingPeopleSectionWhenThereIsAnImportantChild(){
+    fun testInAlertingPeopleSectionWhenThereIsAnImportantChild() {
         // GIVEN
         val altChildA = NotificationEntryBuilder().setTag("A")
                 .setImportance(IMPORTANCE_DEFAULT).build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index 4a94dc8..ac2aec6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -19,13 +19,23 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
-import org.junit.Assert
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
@@ -34,15 +44,45 @@
 
     private val dumpManager: DumpManager = mock()
     private val groupMembershipManager: GroupMembershipManager = mock()
-    private val featureFlags = FakeFeatureFlags()
+    private val featureFlags = FakeFeatureFlagsClassic()
 
-    private val entry1 = NotificationEntryBuilder().build()
-    private val entry2 = NotificationEntryBuilder().build()
+    private val pipeline: NotifPipeline = mock()
+    private lateinit var beforeRenderListListener: OnBeforeRenderListListener
+
+    private val summary1 = notificationEntry("foo", 1)
+    private val summary2 = notificationEntry("bar", 1)
+    private val entries =
+        listOf<ListEntry>(
+            GroupEntryBuilder()
+                .setSummary(summary1)
+                .setChildren(
+                    listOf(
+                        notificationEntry("foo", 2),
+                        notificationEntry("foo", 3),
+                        notificationEntry("foo", 4)
+                    )
+                )
+                .build(),
+            GroupEntryBuilder()
+                .setSummary(summary2)
+                .setChildren(
+                    listOf(
+                        notificationEntry("bar", 2),
+                        notificationEntry("bar", 3),
+                        notificationEntry("bar", 4)
+                    )
+                )
+                .build(),
+            notificationEntry("baz", 1)
+        )
+
+    private fun notificationEntry(pkg: String, id: Int) =
+        NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply { row = mock() }
 
     @Before
     fun setUp() {
-        whenever(groupMembershipManager.getGroupSummary(entry1)).thenReturn(entry1)
-        whenever(groupMembershipManager.getGroupSummary(entry2)).thenReturn(entry2)
+        whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1)
+        whenever(groupMembershipManager.getGroupSummary(summary2)).thenReturn(summary2)
 
         gem = GroupExpansionManagerImpl(dumpManager, groupMembershipManager, featureFlags)
     }
@@ -54,16 +94,16 @@
         var listenerCalledCount = 0
         gem.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
 
-        gem.setGroupExpanded(entry1, false)
-        Assert.assertEquals(0, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(1, listenerCalledCount)
-        gem.setGroupExpanded(entry2, true)
-        Assert.assertEquals(2, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(2, listenerCalledCount)
-        gem.setGroupExpanded(entry2, false)
-        Assert.assertEquals(3, listenerCalledCount)
+        gem.setGroupExpanded(summary1, false)
+        assertThat(listenerCalledCount).isEqualTo(0)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(1)
+        gem.setGroupExpanded(summary2, true)
+        assertThat(listenerCalledCount).isEqualTo(2)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(2)
+        gem.setGroupExpanded(summary2, false)
+        assertThat(listenerCalledCount).isEqualTo(3)
     }
 
     @Test
@@ -73,15 +113,39 @@
         var listenerCalledCount = 0
         gem.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
 
-        gem.setGroupExpanded(entry1, false)
-        Assert.assertEquals(1, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(2, listenerCalledCount)
-        gem.setGroupExpanded(entry2, true)
-        Assert.assertEquals(3, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(4, listenerCalledCount)
-        gem.setGroupExpanded(entry2, false)
-        Assert.assertEquals(5, listenerCalledCount)
+        gem.setGroupExpanded(summary1, false)
+        assertThat(listenerCalledCount).isEqualTo(1)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(2)
+        gem.setGroupExpanded(summary2, true)
+        assertThat(listenerCalledCount).isEqualTo(3)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(4)
+        gem.setGroupExpanded(summary2, false)
+        assertThat(listenerCalledCount).isEqualTo(5)
+    }
+
+    @Test
+    fun testSyncWithPipeline() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        gem.attach(pipeline)
+        beforeRenderListListener = withArgCaptor {
+            verify(pipeline).addOnBeforeRenderListListener(capture())
+        }
+
+        val listener: OnGroupExpansionChangeListener = mock()
+        gem.registerGroupExpansionChangeListener(listener)
+
+        beforeRenderListListener.onBeforeRenderList(entries)
+        verify(listener, never()).onGroupExpansionChange(any(), any())
+
+        // Expand one of the groups.
+        gem.setGroupExpanded(summary1, true)
+        verify(listener).onGroupExpansionChange(summary1.row, true)
+
+        // Empty the pipeline list and verify that the group is no longer expanded.
+        beforeRenderListListener.onBeforeRenderList(emptyList())
+        verify(listener).onGroupExpansionChange(summary1.row, false)
+        verifyNoMoreInteractions(listener)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
new file mode 100644
index 0000000..37ec0e0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.render
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class GroupMembershipManagerTest : SysuiTestCase() {
+    private lateinit var gmm: GroupMembershipManagerImpl
+
+    private val featureFlags = FakeFeatureFlagsClassic()
+
+    @Before
+    fun setUp() {
+        gmm = GroupMembershipManagerImpl(featureFlags)
+    }
+
+    @Test
+    fun testIsChildInGroup_topLevel() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+        assertThat(gmm.isChildInGroup(topLevelEntry)).isFalse()
+    }
+
+    @Test
+    fun testIsChildInGroup_noParent_old() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val noParentEntry = NotificationEntryBuilder().setParent(null).build()
+        assertThat(gmm.isChildInGroup(noParentEntry)).isTrue()
+    }
+
+    @Test
+    fun testIsChildInGroup_noParent_new() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        val noParentEntry = NotificationEntryBuilder().setParent(null).build()
+        assertThat(gmm.isChildInGroup(noParentEntry)).isFalse()
+    }
+
+    @Test
+    fun testIsChildInGroup_child() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val childEntry = NotificationEntryBuilder().build()
+        assertThat(gmm.isChildInGroup(childEntry)).isTrue()
+    }
+
+    @Test
+    fun testIsGroupSummary() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+        assertThat(gmm.isGroupSummary(entry)).isTrue()
+    }
+
+    @Test
+    fun testGetGroupSummary() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+
+        val summary =
+            NotificationEntryBuilder()
+                .setGroup(mContext, "group")
+                .setGroupSummary(mContext, true)
+                .build()
+        val groupEntry =
+            GroupEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).setSummary(summary).build()
+        val entry =
+            NotificationEntryBuilder().setGroup(mContext, "group").setParent(groupEntry).build()
+
+        assertThat(gmm.getGroupSummary(entry)).isEqualTo(summary)
+    }
+
+    @Test
+    fun testGetGroupSummary_isSummary_old() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+        assertThat(gmm.getGroupSummary(entry)).isNull()
+    }
+
+    @Test
+    fun testGetGroupSummary_isSummary_new() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+        assertThat(gmm.getGroupSummary(entry)).isEqualTo(entry)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 7117c23..bbf0151 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -40,8 +40,14 @@
 import com.android.internal.logging.InstanceId;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
+import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.shade.ShadeExpansionStateManager;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
+import com.android.systemui.keyguard.shared.model.WakeSleepReason;
+import com.android.systemui.keyguard.shared.model.WakefulnessModel;
+import com.android.systemui.keyguard.shared.model.WakefulnessState;
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
@@ -54,7 +60,9 @@
 import com.android.systemui.statusbar.notification.logging.nano.Notifications;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
 
 import com.google.android.collect.Lists;
@@ -71,6 +79,8 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Executor;
 
+import kotlinx.coroutines.test.TestScope;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -89,7 +99,7 @@
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
     @Mock private NotifPipeline mNotifPipeline;
     @Mock private NotificationListener mListener;
-    @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
+    @Mock private HeadsUpManager mHeadsUpManager;
 
     private NotificationEntry mEntry;
     private TestableNotificationLogger mLogger;
@@ -97,12 +107,23 @@
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
     private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
             new NotificationPanelLoggerFake();
+    private final TestScope mTestScope = TestScopeProvider.getTestScope();
+    private final FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
+    private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
+    private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mNotifLiveDataStore.getActiveNotifList()).thenReturn(mActiveNotifEntries);
 
+        mWindowRootViewVisibilityInteractor = new WindowRootViewVisibilityInteractor(
+                mTestScope.getBackgroundScope(),
+                new WindowRootViewVisibilityRepository(mBarService, mUiBgExecutor),
+                mKeyguardRepository,
+                mHeadsUpManager);
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
+
         mEntry = new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_NAME)
                 .setOpPkg(TEST_PACKAGE_NAME)
@@ -120,10 +141,12 @@
                 mVisibilityProvider,
                 mNotifPipeline,
                 mock(StatusBarStateControllerImpl.class),
-                mShadeExpansionStateManager,
+                mWindowRootViewVisibilityInteractor,
+                mJavaAdapter,
                 mBarService,
                 mExpansionStateLogger
         );
+        mLogger.start();
         mLogger.setUpWithContainer(mListContainer);
         verify(mNotifPipeline).addCollectionListener(any());
     }
@@ -183,31 +206,26 @@
         Mockito.reset(mBarService);
 
         setStateAsleep();
-        mLogger.onDozingChanged(false);  // Wake to lockscreen
-        mLogger.onDozingChanged(true);  // And go back to sleep, turning off logging
+
+        setStateAwake();  // Wake to lockscreen
+
+        setStateAsleep();  // And go back to sleep, turning off logging
         mUiBgExecutor.runAllReady();
+
         // The visibility objects are recycled by NotificationLogger, so we can't use specific
         // matchers here.
         verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
     }
 
-    private void setStateAsleep() {
-        mLogger.onShadeExpansionFullyChanged(true);
-        mLogger.onDozingChanged(true);
-        mLogger.onStateChanged(StatusBarState.KEYGUARD);
-    }
-
-    private void setStateAwake() {
-        mLogger.onShadeExpansionFullyChanged(false);
-        mLogger.onDozingChanged(false);
-        mLogger.onStateChanged(StatusBarState.SHADE);
-    }
-
     @Test
-    public void testLogPanelShownOnWake() {
+    public void testLogPanelShownOnWakeToLockscreen() {
         when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry));
         setStateAsleep();
-        mLogger.onDozingChanged(false);  // Wake to lockscreen
+
+        // Wake to lockscreen
+        mLogger.onStateChanged(StatusBarState.KEYGUARD);
+        setStateAwake();
+
         assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
         assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
         assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
@@ -222,9 +240,14 @@
     @Test
     public void testLogPanelShownOnShadePull() {
         when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(mEntry));
+        // Start as awake, but with the panel not visible
         setStateAwake();
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
+
         // Now expand panel
-        mLogger.onShadeExpansionFullyChanged(true);
+        mLogger.onStateChanged(StatusBarState.SHADE);
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
+
         assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
         assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
         assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
@@ -251,13 +274,34 @@
 
         when(mActiveNotifEntries.getValue()).thenReturn(Lists.newArrayList(entry));
         setStateAsleep();
-        mLogger.onDozingChanged(false);  // Wake to lockscreen
+
+        // Wake to lockscreen
+        setStateAwake();
+
         assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
         assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
         Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
         assertEquals(0, n.instanceId);
     }
 
+    private void setStateAsleep() {
+        mKeyguardRepository.setWakefulnessModel(
+                new WakefulnessModel(
+                        WakefulnessState.ASLEEP,
+                        WakeSleepReason.OTHER,
+                        WakeSleepReason.OTHER));
+        mTestScope.getTestScheduler().runCurrent();
+    }
+
+    private void setStateAwake() {
+        mKeyguardRepository.setWakefulnessModel(
+                new WakefulnessModel(
+                        WakefulnessState.AWAKE,
+                        WakeSleepReason.OTHER,
+                        WakeSleepReason.OTHER));
+        mTestScope.getTestScheduler().runCurrent();
+    }
+
     private class TestableNotificationLogger extends NotificationLogger {
 
         TestableNotificationLogger(NotificationListener notificationListener,
@@ -266,7 +310,8 @@
                 NotificationVisibilityProvider visibilityProvider,
                 NotifPipeline notifPipeline,
                 StatusBarStateControllerImpl statusBarStateController,
-                ShadeExpansionStateManager shadeExpansionStateManager,
+                WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
+                JavaAdapter javaAdapter,
                 IStatusBarService barService,
                 ExpansionStateLogger expansionStateLogger) {
             super(
@@ -276,7 +321,8 @@
                     visibilityProvider,
                     notifPipeline,
                     statusBarStateController,
-                    shadeExpansionStateManager,
+                    windowRootViewVisibilityInteractor,
+                    javaAdapter,
                     expansionStateLogger,
                     mNotificationPanelLoggerFake
             );
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 0cc0b98..7c8199e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -27,7 +27,6 @@
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.plugins.FalsingManager
@@ -57,6 +56,7 @@
 import com.android.systemui.util.mockito.withArgCaptor
 import com.android.systemui.util.time.SystemClock
 import com.android.systemui.wmshell.BubblesManager
+import java.util.Optional
 import junit.framework.Assert
 import org.junit.After
 import org.junit.Before
@@ -68,7 +68,6 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
-import java.util.Optional
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -100,7 +99,6 @@
     private val gutsManager: NotificationGutsManager = mock()
     private val onUserInteractionCallback: OnUserInteractionCallback = mock()
     private val falsingManager: FalsingManager = mock()
-    private val falsingCollector: FalsingCollector = mock()
     private val featureFlags: FeatureFlags = mock()
     private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
     private val bubblesManager: BubblesManager = mock()
@@ -140,7 +138,6 @@
                 /*allowLongPress=*/ false,
                 onUserInteractionCallback,
                 falsingManager,
-                falsingCollector,
                 featureFlags,
                 peopleNotificationIdentifier,
                 Optional.of(bubblesManager),
@@ -226,20 +223,20 @@
     fun registerSettingsListener_forBubbles() {
         controller.init(mock(NotificationEntry::class.java))
         val viewStateObserver = withArgCaptor {
-            verify(view).addOnAttachStateChangeListener(capture());
+            verify(view).addOnAttachStateChangeListener(capture())
         }
-        viewStateObserver.onViewAttachedToWindow(view);
-        verify(settingsController).addCallback(any(), any());
+        viewStateObserver.onViewAttachedToWindow(view)
+        verify(settingsController).addCallback(any(), any())
     }
 
     @Test
     fun unregisterSettingsListener_forBubbles() {
         controller.init(mock(NotificationEntry::class.java))
         val viewStateObserver = withArgCaptor {
-            verify(view).addOnAttachStateChangeListener(capture());
+            verify(view).addOnAttachStateChangeListener(capture())
         }
-        viewStateObserver.onViewDetachedFromWindow(view);
-        verify(settingsController).removeCallback(any(), any());
+        viewStateObserver.onViewDetachedFromWindow(view)
+        verify(settingsController).removeCallback(any(), any())
     }
 
     @Test
@@ -263,11 +260,17 @@
         whenever(view.privateLayout).thenReturn(childView)
 
         controller.mSettingsListener.onSettingChanged(
-                BUBBLES_SETTING_URI, view.entry.sbn.userId, "1")
+            BUBBLES_SETTING_URI,
+            view.entry.sbn.userId,
+            "1"
+        )
         verify(childView).setBubblesEnabledForUser(true)
 
         controller.mSettingsListener.onSettingChanged(
-                BUBBLES_SETTING_URI, view.entry.sbn.userId, "9")
+            BUBBLES_SETTING_URI,
+            view.entry.sbn.userId,
+            "9"
+        )
         verify(childView).setBubblesEnabledForUser(false)
     }
 
@@ -277,13 +280,12 @@
         whenever(view.privateLayout).thenReturn(childView)
 
         val notification = Notification.Builder(mContext).build()
-        val sbn = SbnBuilder().setNotification(notification)
-                .setUser(UserHandle.of(USER_ALL))
-                .build()
-        whenever(view.entry).thenReturn(NotificationEntryBuilder()
-                .setSbn(sbn)
-                .setUser(UserHandle.of(USER_ALL))
-                .build())
+        val sbn =
+            SbnBuilder().setNotification(notification).setUser(UserHandle.of(USER_ALL)).build()
+        whenever(view.entry)
+            .thenReturn(
+                NotificationEntryBuilder().setSbn(sbn).setUser(UserHandle.of(USER_ALL)).build()
+            )
 
         controller.mSettingsListener.onSettingChanged(BUBBLES_SETTING_URI, 9, "1")
         verify(childView).setBubblesEnabledForUser(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index ea87c80..e52cb57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -135,7 +135,8 @@
                 mock(MediaFeatureFlag.class),
                 mock(Executor.class),
                 mSmartReplyStateInflater,
-                mNotifLayoutInflaterFactoryProvider);
+                mNotifLayoutInflaterFactoryProvider,
+                mock(NotificationContentInflaterLogger.class));
     }
 
     @Test
@@ -258,7 +259,8 @@
                         return new AsyncFailRemoteView(mContext.getPackageName(),
                                 R.layout.custom_view_dark);
                     }
-                });
+                },
+                mock(NotificationContentInflaterLogger.class));
         assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 705d52b..9e0f83c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -37,6 +37,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 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;
@@ -66,11 +67,16 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -84,6 +90,9 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.kotlin.JavaAdapter;
+import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.wmshell.BubblesManager;
 
 import org.junit.Before;
@@ -97,6 +106,8 @@
 
 import java.util.Optional;
 
+import kotlinx.coroutines.test.TestScope;
+
 /**
  * Tests for {@link NotificationGutsManager}.
  */
@@ -108,6 +119,10 @@
 
     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
+
+    private TestScope mTestScope = TestScopeProvider.getTestScope();
+    private JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
+    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private TestableLooper mTestableLooper;
     private Handler mHandler;
     private NotificationTestHelper mHelper;
@@ -124,6 +139,7 @@
     @Mock private AccessibilityManager mAccessibilityManager;
     @Mock private HighPriorityProvider mHighPriorityProvider;
     @Mock private INotificationManager mINotificationManager;
+    @Mock private IStatusBarService mBarService;
     @Mock private LauncherApps mLauncherApps;
     @Mock private ShortcutManager mShortcutManager;
     @Mock private ChannelEditorDialogController mChannelEditorDialogController;
@@ -140,6 +156,8 @@
 
     @Mock private UserManager mUserManager;
 
+    private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
+
     @Before
     public void setUp() {
         mTestableLooper = TestableLooper.get(this);
@@ -148,21 +166,42 @@
         mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
 
-        mGutsManager = new NotificationGutsManager(mContext, mHandler, mHandler,
+        mWindowRootViewVisibilityInteractor = new WindowRootViewVisibilityInteractor(
+                mTestScope.getBackgroundScope(),
+                new WindowRootViewVisibilityRepository(mBarService, mExecutor),
+                new FakeKeyguardRepository(),
+                mHeadsUpManagerPhone);
+
+        mGutsManager = new NotificationGutsManager(
+                mContext,
+                mHandler,
+                mHandler,
+                mJavaAdapter,
                 mAccessibilityManager,
-                mHighPriorityProvider, mINotificationManager, mUserManager,
-                mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager,
-                mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController,
-                Optional.of(mBubblesManager), new UiEventLoggerFake(), mOnUserInteractionCallback,
+                mHighPriorityProvider,
+                mINotificationManager,
+                mUserManager,
+                mPeopleSpaceWidgetManager,
+                mLauncherApps,
+                mShortcutManager,
+                mChannelEditorDialogController,
+                mContextTracker,
+                mAssistantFeedbackController,
+                Optional.of(mBubblesManager),
+                new UiEventLoggerFake(),
+                mOnUserInteractionCallback,
                 mShadeController,
+                mWindowRootViewVisibilityInteractor,
                 mNotificationLockscreenUserManager,
                 mStatusBarStateController,
                 mDeviceProvisionedController,
                 mMetricsLogger,
-                mHeadsUpManagerPhone, mActivityStarter);
+                mHeadsUpManagerPhone,
+                mActivityStarter);
         mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
                 mOnSettingsClickListener);
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
+        mGutsManager.start();
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////
@@ -210,6 +249,62 @@
     }
 
     @Test
+    public void testLockscreenShadeVisible_visible_gutsNotClosed() {
+        // First, start out lockscreen or shade as not visible
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
+        mTestScope.getTestScheduler().runCurrent();
+
+        NotificationGuts guts = mock(NotificationGuts.class);
+        mGutsManager.setExposedGuts(guts);
+
+        // WHEN the lockscreen or shade becomes visible
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
+        mTestScope.getTestScheduler().runCurrent();
+
+        // THEN the guts are not closed
+        verify(guts, never()).removeCallbacks(any());
+        verify(guts, never()).closeControls(
+                anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
+    }
+
+    @Test
+    public void testLockscreenShadeVisible_notVisible_gutsClosed() {
+        // First, start out lockscreen or shade as visible
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
+        mTestScope.getTestScheduler().runCurrent();
+
+        NotificationGuts guts = mock(NotificationGuts.class);
+        mGutsManager.setExposedGuts(guts);
+
+        // WHEN the lockscreen or shade is no longer visible
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
+        mTestScope.getTestScheduler().runCurrent();
+
+        // THEN the guts are closed
+        verify(guts).removeCallbacks(any());
+        verify(guts).closeControls(
+                /* leavebehinds= */ eq(true),
+                /* controls= */ eq(true),
+                /* x= */ anyInt(),
+                /* y= */ anyInt(),
+                /* force= */ eq(true));
+    }
+
+    @Test
+    public void testLockscreenShadeVisible_notVisible_listContainerReset() {
+        // First, start out lockscreen or shade as visible
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
+        mTestScope.getTestScheduler().runCurrent();
+
+        // WHEN the lockscreen or shade is no longer visible
+        mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
+        mTestScope.getTestScheduler().runCurrent();
+
+        // THEN the list container is reset
+        verify(mNotificationListContainer).resetExposedMenuView(anyBoolean(), anyBoolean());
+    }
+
+    @Test
     public void testChangeDensityOrFontScale() {
         NotificationGuts guts = spy(new NotificationGuts(mContext));
         when(guts.post(any())).thenAnswer(invocation -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 0425830..6386940 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -54,7 +54,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.TestableDependency;
-import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.flags.FeatureFlags;
@@ -175,7 +174,8 @@
                 mock(MediaFeatureFlag.class),
                 mock(Executor.class),
                 new MockSmartReplyInflater(),
-                mock(NotifLayoutInflaterFactory.Provider.class));
+                mock(NotifLayoutInflaterFactory.Provider.class),
+                mock(NotificationContentInflaterLogger.class));
         contentBinder.setInflateSynchronously(true);
         mBindStage = new RowContentBindStage(contentBinder,
                 mock(NotifInflationErrorManager.class),
@@ -600,7 +600,6 @@
                 mock(OnExpandClickListener.class),
                 mock(ExpandableNotificationRow.CoordinateOnClickListener.class),
                 new FalsingManagerFake(),
-                new FalsingCollectorFake(),
                 mStatusBarStateController,
                 mPeopleNotificationIdentifier,
                 mOnUserInteractionCallback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 55b52dc..75fb22d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
 import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.shade.data.repository.FakeShadeRepository
@@ -97,7 +98,11 @@
                 keyguardTransitionInteractor = it.keyguardTransitionInteractor
                 keyguardTransitionRepository = it.repository
             }
-
+        sharedNotificationContainerInteractor =
+            SharedNotificationContainerInteractor(
+                configurationRepository,
+                mContext,
+            )
         shadeInteractor =
             ShadeInteractor(
                 testScope.backgroundScope,
@@ -106,14 +111,9 @@
                 userSetupRepository,
                 deviceProvisionedController,
                 userInteractor,
+                sharedNotificationContainerInteractor,
                 shadeRepository,
             )
-
-        sharedNotificationContainerInteractor =
-            SharedNotificationContainerInteractor(
-                configurationRepository,
-                mContext,
-            )
         underTest =
             SharedNotificationContainerViewModel(
                 sharedNotificationContainerInteractor,
@@ -228,7 +228,7 @@
             val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade)
 
             // First on AOD
-            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setLockscreenShadeExpansion(0f)
             shadeRepository.setQsExpansion(0f)
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -242,19 +242,19 @@
             showLockscreen()
 
             // While state is LOCKSCREEN, validate variations of both shade and qs expansion
-            shadeRepository.setShadeExpansion(0.1f)
+            shadeRepository.setLockscreenShadeExpansion(0.1f)
             shadeRepository.setQsExpansion(0f)
             assertThat(isOnLockscreenWithoutShade).isFalse()
 
-            shadeRepository.setShadeExpansion(0.1f)
+            shadeRepository.setLockscreenShadeExpansion(0.1f)
             shadeRepository.setQsExpansion(0.1f)
             assertThat(isOnLockscreenWithoutShade).isFalse()
 
-            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setLockscreenShadeExpansion(0f)
             shadeRepository.setQsExpansion(0.1f)
             assertThat(isOnLockscreenWithoutShade).isFalse()
 
-            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setLockscreenShadeExpansion(0f)
             shadeRepository.setQsExpansion(0f)
             assertThat(isOnLockscreenWithoutShade).isTrue()
         }
@@ -366,8 +366,9 @@
         }
 
     private suspend fun showLockscreen() {
-        shadeRepository.setShadeExpansion(0f)
+        shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(0f)
+        keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
         keyguardTransitionRepository.sendTransitionStep(
             TransitionStep(
                 to = KeyguardState.LOCKSCREEN,
@@ -377,8 +378,9 @@
     }
 
     private suspend fun showLockscreenWithShadeExpanded() {
-        shadeRepository.setShadeExpansion(1f)
+        shadeRepository.setLockscreenShadeExpansion(1f)
         shadeRepository.setQsExpansion(0f)
+        keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
         keyguardTransitionRepository.sendTransitionStep(
             TransitionStep(
                 to = KeyguardState.LOCKSCREEN,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index f47efe3..137566b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -24,7 +24,6 @@
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
-import static junit.framework.TestCase.fail;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -62,7 +61,6 @@
 import android.os.IThermalService;
 import android.os.Looper;
 import android.os.PowerManager;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.dreams.IDreamManager;
 import android.support.test.metricshelper.MetricsAsserts;
@@ -73,13 +71,7 @@
 import android.util.SparseArray;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
-import android.view.ViewRootImpl;
 import android.view.WindowManager;
-import android.window.BackEvent;
-import android.window.OnBackAnimationCallback;
-import android.window.OnBackInvokedCallback;
-import android.window.OnBackInvokedDispatcher;
-import android.window.WindowOnBackInvokedDispatcher;
 
 import androidx.test.filters.SmallTest;
 
@@ -125,6 +117,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.settings.brightness.BrightnessSliderController;
 import com.android.systemui.shade.CameraLauncher;
@@ -143,6 +136,7 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -158,7 +152,6 @@
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -167,13 +160,10 @@
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -199,7 +189,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -207,6 +196,8 @@
 import java.io.PrintWriter;
 import java.util.Optional;
 
+import javax.inject.Provider;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -227,7 +218,6 @@
     @Mock private KeyguardIndicationController mKeyguardIndicationController;
     @Mock private NotificationStackScrollLayout mStackScroller;
     @Mock private NotificationStackScrollLayoutController mStackScrollerController;
-    @Mock private NotificationListContainer mNotificationListContainer;
     @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private NotificationPanelViewController mNotificationPanelViewController;
     @Mock private ShadeLogger mShadeLogger;
@@ -254,7 +244,6 @@
     @Mock private StatusBarNotificationPresenter mNotificationPresenter;
     @Mock private NotificationActivityStarter mNotificationActivityStarter;
     @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
-    @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private StatusBarSignalPolicy mStatusBarSignalPolicy;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
@@ -273,6 +262,7 @@
     @Mock private DynamicPrivacyController mDynamicPrivacyController;
     @Mock private AutoHideController mAutoHideController;
     @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private Provider<CollapsedStatusBarFragment> mCollapsedStatusBarFragmentProvider;
     @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private UserSwitcherController mUserSwitcherController;
     @Mock private Bubbles mBubbles;
@@ -291,8 +281,6 @@
     @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
     @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
-    @Mock private CentralSurfacesComponent.Factory mStatusBarComponentFactory;
-    @Mock private CentralSurfacesComponent mCentralSurfacesComponent;
     @Mock private CentralSurfacesCommandQueueCallbacks mCentralSurfacesCommandQueueCallbacks;
     @Mock private PluginManager mPluginManager;
     @Mock private ViewMediatorCallback mViewMediatorCallback;
@@ -325,18 +313,11 @@
     @Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
     @Mock private CameraLauncher mCameraLauncher;
     @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
-    /**
-     * The process of registering/unregistering a predictive back callback requires a
-     * ViewRootImpl, which is present IRL, but may be missing during a Mockito unit test.
-     * To prevent an NPE during test execution, we explicitly craft and provide a fake ViewRootImpl.
-     */
-    @Mock private ViewRootImpl mViewRootImpl;
-    @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
     @Mock private UserTracker mUserTracker;
     @Mock private FingerprintManager mFingerprintManager;
-    @Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
     @Mock IPowerManager mPowerManagerService;
     @Mock ActivityStarter mActivityStarter;
+    @Mock private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
 
     private ShadeController mShadeController;
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -388,18 +369,6 @@
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
 
         mMetricsLogger = new FakeMetricsLogger();
-        NotificationLogger notificationLogger = new NotificationLogger(
-                mNotificationListener,
-                mUiBgExecutor,
-                mNotifLiveDataStore,
-                mVisibilityProvider,
-                mock(NotifPipeline.class),
-                mStatusBarStateController,
-                mShadeExpansionStateManager,
-                mExpansionStateLogger,
-                new NotificationPanelLoggerFake()
-        );
-        notificationLogger.setVisibilityReporter(mock(Runnable.class));
 
         when(mCommandQueue.asBinder()).thenReturn(new Binder());
 
@@ -438,7 +407,6 @@
         when(mNotificationShadeWindowViewControllerLazy.get())
                 .thenReturn(mNotificationShadeWindowViewController);
 
-        when(mStatusBarComponentFactory.create()).thenReturn(mCentralSurfacesComponent);
         doAnswer(invocation -> {
             ((Runnable) invocation.getArgument(0)).run();
             return null;
@@ -448,6 +416,7 @@
                 mCommandQueue,
                 mMainExecutor,
                 mock(LogBuffer.class),
+                mock(WindowRootViewVisibilityInteractor.class),
                 mKeyguardStateController,
                 mStatusBarStateController,
                 mStatusBarKeyguardViewManager,
@@ -475,7 +444,10 @@
                 mock(FragmentService.class),
                 mLightBarController,
                 mAutoHideController,
-                new StatusBarInitializer(mStatusBarWindowController, emptySet()),
+                new StatusBarInitializer(
+                        mStatusBarWindowController,
+                        mCollapsedStatusBarFragmentProvider,
+                        emptySet()),
                 mStatusBarWindowController,
                 mStatusBarWindowStateController,
                 mKeyguardUpdateMonitor,
@@ -490,7 +462,6 @@
                 new FalsingCollectorFake(),
                 mBroadcastDispatcher,
                 mNotificationGutsManager,
-                notificationLogger,
                 mNotificationInterruptStateProvider,
                 new ShadeExpansionStateManager(),
                 mKeyguardViewMediator,
@@ -521,8 +492,8 @@
                 mNotificationShadeWindowViewControllerLazy,
                 mNotificationShelfController,
                 mStackScrollerController,
-                mNotificationPresenter,
-                mNotificationActivityStarter,
+                (Lazy<NotificationPresenter>) () -> mNotificationPresenter,
+                (Lazy<NotificationActivityStarter>) () -> mNotificationActivityStarter,
                 mNotifLaunchAnimControllerProvider,
                 new NotificationExpansionRepository(),
                 mDozeParameters,
@@ -537,10 +508,10 @@
                 mDozeScrimController,
                 mVolumeComponent,
                 mCommandQueue,
-                mStatusBarComponentFactory,
                 () -> mCentralSurfacesCommandQueueCallbacks,
                 mPluginManager,
                 mShadeController,
+                mWindowRootViewVisibilityInteractor,
                 mStatusBarKeyguardViewManager,
                 mViewMediatorCallback,
                 mInitController,
@@ -578,16 +549,9 @@
                 mUserTracker,
                 () -> mFingerprintManager,
                 mActivityStarter
-        ) {
-            @Override
-            protected ViewRootImpl getViewRootImpl() {
-                return mViewRootImpl;
-            }
-        };
+        );
         mScreenLifecycle.addObserver(mCentralSurfaces.mScreenObserver);
         mCentralSurfaces.initShadeVisibilityListener();
-        when(mViewRootImpl.getOnBackInvokedDispatcher())
-                .thenReturn(mOnBackInvokedDispatcher);
         when(mKeyguardViewMediator.registerCentralSurfaces(
                 any(CentralSurfacesImpl.class),
                 any(NotificationPanelViewController.class),
@@ -609,7 +573,6 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "sysui:GestureWakeLock");
         mCentralSurfaces.startKeyguard();
         mInitController.executePostInitTasks();
-        notificationLogger.setUpWithContainer(mNotificationListContainer);
         mCentralSurfaces.registerCallbacks();
     }
 
@@ -799,151 +762,6 @@
     }
 
     @Test
-    public void testLogHidden() {
-        try {
-            mCentralSurfaces.handleVisibleToUserChanged(false);
-            mUiBgExecutor.runAllReady();
-            verify(mBarService, times(1)).onPanelHidden();
-            verify(mBarService, never()).onPanelRevealed(anyBoolean(), anyInt());
-        } catch (RemoteException e) {
-            fail();
-        }
-    }
-
-    /**
-     * Do the following:
-     * 1. verify that a predictive back callback is registered when CSurf becomes visible
-     * 2. verify that the same callback is unregistered when CSurf becomes invisible
-     */
-    @Test
-    public void testPredictiveBackCallback_registration() {
-        mCentralSurfaces.handleVisibleToUserChanged(true);
-        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
-                mOnBackInvokedCallback.capture());
-
-        mCentralSurfaces.handleVisibleToUserChanged(false);
-        verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
-                eq(mOnBackInvokedCallback.getValue()));
-    }
-
-    /**
-     * Do the following:
-     * 1. capture the predictive back callback during registration
-     * 2. call the callback directly
-     * 3. verify that the ShadeController's panel collapse animation is invoked
-     */
-    @Test
-    public void testPredictiveBackCallback_invocationCollapsesPanel() {
-        mCentralSurfaces.handleVisibleToUserChanged(true);
-        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
-                mOnBackInvokedCallback.capture());
-
-        when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
-        mOnBackInvokedCallback.getValue().onBackInvoked();
-        verify(mBackActionInteractor).onBackRequested();
-    }
-
-    /**
-     * When back progress is at 100%, the onBackProgressed animation driver inside
-     * NotificationPanelViewController should be invoked appropriately (with 1.0f passed in).
-     */
-    @Test
-    public void testPredictiveBackAnimation_progressMaxScalesPanel() {
-        mCentralSurfaces.handleVisibleToUserChanged(true);
-        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
-                mOnBackInvokedCallback.capture());
-
-        OnBackAnimationCallback onBackAnimationCallback =
-                (OnBackAnimationCallback) (mOnBackInvokedCallback.getValue());
-        when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
-        when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
-
-        BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 100.0f, 1.0f, BackEvent.EDGE_LEFT);
-        onBackAnimationCallback.onBackProgressed(fakeSwipeInFromLeftEdge);
-        verify(mNotificationPanelViewController).onBackProgressed(eq(1.0f));
-    }
-
-    /**
-     * When back progress is at 0%, the onBackProgressed animation driver inside
-     * NotificationPanelViewController should be invoked appropriately (with 0.0f passed in).
-     */
-    @Test
-    public void testPredictiveBackAnimation_progressMinScalesPanel() {
-        mCentralSurfaces.handleVisibleToUserChanged(true);
-        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
-                mOnBackInvokedCallback.capture());
-
-        OnBackAnimationCallback onBackAnimationCallback =
-                (OnBackAnimationCallback) (mOnBackInvokedCallback.getValue());
-        when(mBackActionInteractor.shouldBackBeHandled()).thenReturn(true);
-        when(mNotificationPanelViewController.canBeCollapsed()).thenReturn(true);
-
-        BackEvent fakeSwipeInFromLeftEdge = new BackEvent(20.0f, 10.0f, 0.0f, BackEvent.EDGE_LEFT);
-        onBackAnimationCallback.onBackProgressed(fakeSwipeInFromLeftEdge);
-        verify(mNotificationPanelViewController).onBackProgressed(eq(0.0f));
-    }
-
-    @Test
-    public void testPanelOpenForHeadsUp() {
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
-        when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5);
-        when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true);
-        mCentralSurfaces.setBarStateForTest(SHADE);
-
-        try {
-            mCentralSurfaces.handleVisibleToUserChanged(true);
-            mUiBgExecutor.runAllReady();
-            verify(mBarService, never()).onPanelHidden();
-            verify(mBarService, times(1)).onPanelRevealed(false, 1);
-        } catch (RemoteException e) {
-            fail();
-        }
-        mMainExecutor.runAllReady();
-    }
-
-    @Test
-    public void testPanelOpenAndClear() {
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5);
-
-        when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
-        mCentralSurfaces.setBarStateForTest(SHADE);
-
-        try {
-            mCentralSurfaces.handleVisibleToUserChanged(true);
-            mUiBgExecutor.runAllReady();
-            verify(mBarService, never()).onPanelHidden();
-            verify(mBarService, times(1)).onPanelRevealed(true, 5);
-        } catch (RemoteException e) {
-            fail();
-        }
-        mMainExecutor.runAllReady();
-    }
-
-    @Test
-    public void testPanelOpenAndNoClear() {
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5);
-        when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
-        mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD);
-
-        try {
-            mCentralSurfaces.handleVisibleToUserChanged(true);
-            mUiBgExecutor.runAllReady();
-            verify(mBarService, never()).onPanelHidden();
-            verify(mBarService, times(1)).onPanelRevealed(false, 5);
-        } catch (RemoteException e) {
-            fail();
-        }
-        mMainExecutor.runAllReady();
-    }
-
-    @Test
     public void testDump_DoesNotCrash() {
         mCentralSurfaces.dump(new PrintWriter(new ByteArrayOutputStream()), null);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 9795b9d..71c27de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.PendingDisplay
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
 import com.android.systemui.privacy.PrivacyItemController
 import com.android.systemui.privacy.logging.PrivacyLogger
@@ -316,5 +317,7 @@
         suspend fun emit(value: State) = flow.emit(value)
         override val connectedDisplayState: Flow<State>
             get() = flow
+        override val pendingDisplay: Flow<PendingDisplay?>
+            get() = TODO("Not yet implemented")
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 4c3c3f9..4349d73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.shade.ShadeControllerImpl
 import com.android.systemui.shade.ShadeLogger
@@ -47,6 +48,8 @@
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import javax.inject.Provider
 import org.junit.Before
 import org.junit.Test
 import org.mockito.ArgumentCaptor
@@ -57,40 +60,24 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
-import java.util.Optional
-import javax.inject.Provider
 
 @SmallTest
 class PhoneStatusBarViewControllerTest : SysuiTestCase() {
 
-    @Mock
-    private lateinit var shadeViewController: ShadeViewController
-    @Mock
-    private lateinit var featureFlags: FeatureFlags
-    @Mock
-    private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
-    @Mock
-    private lateinit var sysuiUnfoldComponent: SysUIUnfoldComponent
-    @Mock
-    private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
-    @Mock
-    private lateinit var configurationController: ConfigurationController
-    @Mock
-    private lateinit var mStatusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory
-    @Mock
-    private lateinit var userChipViewModel: StatusBarUserChipViewModel
-    @Mock
-    private lateinit var centralSurfacesImpl: CentralSurfacesImpl
-    @Mock
-    private lateinit var commandQueue: CommandQueue
-    @Mock
-    private lateinit var shadeControllerImpl: ShadeControllerImpl
-    @Mock
-    private lateinit var windowRootView: Provider<WindowRootView>
-    @Mock
-    private lateinit var shadeLogger: ShadeLogger
-    @Mock
-    private lateinit var viewUtil: ViewUtil
+    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var featureFlags: FeatureFlags
+    @Mock private lateinit var moveFromCenterAnimation: StatusBarMoveFromCenterAnimationController
+    @Mock private lateinit var sysuiUnfoldComponent: SysUIUnfoldComponent
+    @Mock private lateinit var progressProvider: ScopedUnfoldTransitionProgressProvider
+    @Mock private lateinit var configurationController: ConfigurationController
+    @Mock private lateinit var mStatusOverlayHoverListenerFactory: StatusOverlayHoverListenerFactory
+    @Mock private lateinit var userChipViewModel: StatusBarUserChipViewModel
+    @Mock private lateinit var centralSurfacesImpl: CentralSurfacesImpl
+    @Mock private lateinit var commandQueue: CommandQueue
+    @Mock private lateinit var shadeControllerImpl: ShadeControllerImpl
+    @Mock private lateinit var windowRootView: Provider<WindowRootView>
+    @Mock private lateinit var shadeLogger: ShadeLogger
+    @Mock private lateinit var viewUtil: ViewUtil
     private lateinit var statusBarWindowStateController: StatusBarWindowStateController
 
     private lateinit var view: PhoneStatusBarView
@@ -109,16 +96,16 @@
         // create the view and controller on main thread as it requires main looper
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             val parent = FrameLayout(mContext) // add parent to keep layout params
-            view = LayoutInflater.from(mContext)
-                .inflate(R.layout.status_bar, parent, false) as PhoneStatusBarView
+            view =
+                LayoutInflater.from(mContext).inflate(R.layout.status_bar, parent, false)
+                    as PhoneStatusBarView
             controller = createAndInitController(view)
         }
     }
 
     @Test
     fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
-        whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS))
-                .thenReturn(true)
+        whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS)).thenReturn(true)
         val view = createViewMock()
         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
         unfoldConfig.isEnabled = true
@@ -136,7 +123,7 @@
     @Test
     fun onViewAttachedAndDrawn_statusBarAnimationDisabled_animationNotInitialized() {
         whenever(featureFlags.isEnabled(Flags.ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS))
-                .thenReturn(false)
+            .thenReturn(false)
         val view = createViewMock()
         unfoldConfig.isEnabled = true
         // create the controller on main thread as it requires main looper
@@ -150,8 +137,8 @@
     @Test
     fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
         `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
-        val returnVal = view.onTouchEvent(
-                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        val returnVal =
+            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
         assertThat(returnVal).isFalse()
         verify(shadeViewController, never()).handleExternalTouch(any())
     }
@@ -160,8 +147,8 @@
     fun handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
         `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
         `when`(shadeViewController.isViewEnabled).thenReturn(false)
-        val returnVal = view.onTouchEvent(
-                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        val returnVal =
+            view.onTouchEvent(MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
         assertThat(returnVal).isTrue()
         verify(shadeViewController, never()).handleExternalTouch(any())
     }
@@ -245,22 +232,23 @@
 
     private fun createAndInitController(view: PhoneStatusBarView): PhoneStatusBarViewController {
         return PhoneStatusBarViewController.Factory(
-            Optional.of(sysuiUnfoldComponent),
-            Optional.of(progressProvider),
-            featureFlags,
-            userChipViewModel,
-            centralSurfacesImpl,
-            statusBarWindowStateController,
-            shadeControllerImpl,
-            shadeViewController,
-            windowRootView,
-            shadeLogger,
-            viewUtil,
-            configurationController,
-            mStatusOverlayHoverListenerFactory
-        ).create(view).also {
-            it.init()
-        }
+                Optional.of(sysuiUnfoldComponent),
+                Optional.of(progressProvider),
+                featureFlags,
+                FakeSceneContainerFlags(),
+                userChipViewModel,
+                centralSurfacesImpl,
+                statusBarWindowStateController,
+                shadeControllerImpl,
+                shadeViewController,
+                windowRootView,
+                shadeLogger,
+                viewUtil,
+                configurationController,
+                mStatusOverlayHoverListenerFactory
+            )
+            .create(view)
+            .also { it.init() }
     }
 
     private class UnfoldConfig : UnfoldTransitionConfig {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
index 08e89fb..6f04f36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImplTest.kt
@@ -220,30 +220,6 @@
 
     /** Regression test for b/255428281. */
     @Test
-    fun internalAndExternalIconWithSameName_internalRemoved_viaRemoveAll_externalStays() {
-        val slotName = "mute"
-
-        // Internal
-        underTest.setIcon(slotName, /* resourceId= */ 10, "contentDescription")
-
-        // External
-        underTest.setIconFromTile(slotName, createExternalIcon())
-
-        // WHEN the internal icon is removed via #removeAllIconsForSlot
-        underTest.removeAllIconsForSlot(slotName)
-
-        // THEN the internal icon is removed but the external icon remains
-        assertThat(iconList.slots).hasSize(2)
-        assertThat(iconList.slots[0].name).isEqualTo(slotName + EXTERNAL_SLOT_SUFFIX)
-        assertThat(iconList.slots[1].name).isEqualTo(slotName)
-        assertThat(iconList.slots[0].hasIconsInSlot()).isTrue()
-        assertThat(iconList.slots[1].hasIconsInSlot()).isFalse() // Indicates removal
-
-        verify(iconGroup).onRemoveIcon(1)
-    }
-
-    /** Regression test for b/255428281. */
-    @Test
     fun internalAndExternalIconWithSameName_internalUpdatedIndependently() {
         val slotName = "mute"
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index 085ec27..0ff6f20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -120,34 +120,6 @@
         verify(manager, never()).onRemoveIcon(anyInt());
     }
 
-    @Test
-    public void testRemoveAllIconsForSlot_ignoredForNewPipeline() {
-        IconManager manager = mock(IconManager.class);
-
-        // GIVEN the new pipeline is on
-        StatusBarPipelineFlags flags = mock(StatusBarPipelineFlags.class);
-        when(flags.isIconControlledByFlags("test_icon")).thenReturn(true);
-
-        StatusBarIconController iconController = new StatusBarIconControllerImpl(
-                mContext,
-                mock(CommandQueue.class),
-                mock(DemoModeController.class),
-                mock(ConfigurationController.class),
-                mock(TunerService.class),
-                mock(DumpManager.class),
-                mock(StatusBarIconList.class),
-                flags
-        );
-
-        iconController.addIconGroup(manager);
-
-        // WHEN a request to remove a new icon is sent
-        iconController.removeAllIconsForSlot("test_icon");
-
-        // THEN it is not removed for those icons
-        verify(manager, never()).onRemoveIcon(anyInt());
-    }
-
     private <T extends IconManager & TestableIconManager> void testCallOnAdd_forManager(T manager) {
         StatusBarIconHolder holder = holderForType(TYPE_ICON);
         manager.onIconAdded(0, "test_slot", false, holder);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index e76f26d..e6f8c48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -134,6 +134,22 @@
         verify(shadeViewController, times(1)).showAodUi()
     }
 
+    @Test
+    fun testAodUiShowNotInvokedIfWakingUp() {
+        `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true)
+        `when`(powerManager.isInteractive).thenReturn(false)
+
+        val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+        controller.startAnimation()
+        controller.onStartedWakingUp()
+
+        verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
+
+        callbackCaptor.value.run()
+
+        verify(shadeViewController, never()).showAodUi()
+    }
+
     /**
      * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal
      * animation to start. If the device is woken up during the screen off, we should *never* do
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
new file mode 100644
index 0000000..5784be3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/ethernet/domain/EthernetInteractorTest.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.ethernet.domain
+
+import androidx.test.filters.SmallTest
+import com.android.settingslib.AccessibilityContentDescriptions
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+class EthernetInteractorTest : SysuiTestCase() {
+    private val connectivityRepository = FakeConnectivityRepository()
+    private val underTest = EthernetInteractor(connectivityRepository)
+
+    private val testScope = TestScope()
+
+    @Test
+    fun icon_default_validated() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.icon)
+
+            connectivityRepository.setEthernetConnected(default = true, validated = true)
+
+            val expected =
+                Icon.Resource(
+                    R.drawable.stat_sys_ethernet_fully,
+                    ContentDescription.Resource(
+                        AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES[1]
+                    )
+                )
+
+            assertThat(latest).isEqualTo(expected)
+        }
+
+    @Test
+    fun icon_default_notValidated() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.icon)
+
+            connectivityRepository.setEthernetConnected(default = true, validated = false)
+
+            val expected =
+                Icon.Resource(
+                    R.drawable.stat_sys_ethernet,
+                    ContentDescription.Resource(
+                        AccessibilityContentDescriptions.ETHERNET_CONNECTION_VALUES[0]
+                    )
+                )
+
+            assertThat(latest).isEqualTo(expected)
+        }
+
+    @Test
+    fun icon_notDefault_validated() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.icon)
+
+            connectivityRepository.setEthernetConnected(default = false, validated = true)
+
+            assertThat(latest).isNull()
+        }
+
+    @Test
+    fun icon_notDefault_notValidated() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.icon)
+
+            connectivityRepository.setEthernetConnected(default = false, validated = false)
+
+            assertThat(latest).isNull()
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index ff28753..812e91b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -64,6 +64,28 @@
         _dataEnabled.value = enabled
     }
 
+    /**
+     * Set [primaryLevel] and [cdmaLevel]. Convenient when you don't care about the connection type
+     */
+    fun setAllLevels(level: Int) {
+        cdmaLevel.value = level
+        primaryLevel.value = level
+    }
+
+    /**
+     * Set both [isRoaming] and [cdmaRoaming] properties, in the event that you don't care about the
+     * connection type
+     */
+    fun setAllRoaming(roaming: Boolean) {
+        isRoaming.value = roaming
+        cdmaRoaming.value = roaming
+    }
+
+    /** Set the correct [resolvedNetworkType] for the given group via its lookup key */
+    fun setNetworkTypeKey(key: String) {
+        resolvedNetworkType.value = ResolvedNetworkType.DefaultNetworkType(key)
+    }
+
     companion object {
         const val DEFAULT_NETWORK_NAME = "default name"
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 9c0cb17..ede02d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -674,6 +674,7 @@
         val realRepo =
             MobileConnectionRepositoryImpl(
                 SUB_ID,
+                context,
                 subscriptionModel,
                 DEFAULT_NAME_MODEL,
                 SEP,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index e50e5e3..3af960b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -16,18 +16,22 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
 
+import android.content.BroadcastReceiver
+import android.content.Context
 import android.content.Intent
 import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
 import android.telephony.NetworkRegistrationInfo
 import android.telephony.ServiceState
 import android.telephony.ServiceState.STATE_IN_SERVICE
 import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
+import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
 import android.telephony.TelephonyCallback
 import android.telephony.TelephonyCallback.DataActivityListener
 import android.telephony.TelephonyCallback.ServiceStateListener
 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
 import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED
 import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
 import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
 import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
@@ -75,6 +79,7 @@
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
@@ -88,6 +93,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
+import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@@ -100,6 +106,7 @@
     @Mock private lateinit var telephonyManager: TelephonyManager
     @Mock private lateinit var logger: MobileInputLogger
     @Mock private lateinit var tableLogger: TableLogBuffer
+    @Mock private lateinit var context: Context
 
     private val mobileMappings = FakeMobileMappingsProxy()
     private val systemUiCarrierConfig =
@@ -129,6 +136,7 @@
         underTest =
             MobileConnectionRepositoryImpl(
                 SUB_1_ID,
+                context,
                 subscriptionModel,
                 DEFAULT_NAME_MODEL,
                 SEP,
@@ -706,7 +714,9 @@
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
             val intent = spnIntent()
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.value!!.onReceive(context, intent)
 
             assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
@@ -720,13 +730,16 @@
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
             val intent = spnIntent()
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.value!!.onReceive(context, intent)
+
             assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
             // WHEN an intent with a different subId is sent
             val wrongSubIntent = spnIntent(subId = 101)
 
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, wrongSubIntent)
+            captor.value!!.onReceive(context, wrongSubIntent)
 
             // THEN the previous intent's name is still used
             assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
@@ -741,7 +754,10 @@
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
             val intent = spnIntent()
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intent)
+            val captor = argumentCaptor<BroadcastReceiver>()
+            verify(context).registerReceiver(captor.capture(), any())
+            captor.value!!.onReceive(context, intent)
+
             assertThat(latest).isEqualTo(intent.toNetworkNameModel(SEP))
 
             val intentWithoutInfo =
@@ -750,7 +766,7 @@
                     showPlmn = false,
                 )
 
-            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intentWithoutInfo)
+            captor.value!!.onReceive(context, intentWithoutInfo)
 
             assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
 
@@ -893,7 +909,7 @@
         plmn: String = PLMN,
     ): Intent =
         Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply {
-            putExtra(EXTRA_SUBSCRIPTION_ID, subId)
+            putExtra(EXTRA_SUBSCRIPTION_INDEX, subId)
             putExtra(EXTRA_SHOW_SPN, showSpn)
             putExtra(EXTRA_SPN, spn)
             putExtra(EXTRA_SHOW_PLMN, showPlmn)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index ea60aa7..852ed20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -125,6 +125,7 @@
         underTest =
             MobileConnectionRepositoryImpl(
                 SUB_1_ID,
+                context,
                 subscriptionModel,
                 DEFAULT_NAME,
                 SEP,
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 fd05cc4..6f9764a 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
@@ -175,6 +175,7 @@
 
         connectionFactory =
             MobileConnectionRepositoryImpl.Factory(
+                context,
                 fakeBroadcastDispatcher,
                 telephonyManager = telephonyManager,
                 bgDispatcher = dispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index a3df785..de2b6a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -16,12 +16,11 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
 
-import android.telephony.CellSignalStrength
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import kotlinx.coroutines.flow.MutableStateFlow
 
@@ -30,8 +29,6 @@
 ) : MobileIconInteractor {
     override val alwaysShowDataRatIcon = MutableStateFlow(false)
 
-    override val alwaysUseCdmaLevel = MutableStateFlow(false)
-
     override val activity =
         MutableStateFlow(
             DataActivityModel(
@@ -55,14 +52,8 @@
 
     override val carrierName = MutableStateFlow("demo mode")
 
-    private val _isEmergencyOnly = MutableStateFlow(false)
-    override val isEmergencyOnly = _isEmergencyOnly
-
     override val isRoaming = MutableStateFlow(false)
 
-    private val _isFailedConnection = MutableStateFlow(false)
-    override val isDefaultConnectionFailed = _isFailedConnection
-
     override val isDataConnected = MutableStateFlow(true)
 
     override val isInService = MutableStateFlow(true)
@@ -70,40 +61,21 @@
     private val _isDataEnabled = MutableStateFlow(true)
     override val isDataEnabled = _isDataEnabled
 
-    private val _isDefaultDataEnabled = MutableStateFlow(true)
-    override val isDefaultDataEnabled = _isDefaultDataEnabled
-
-    private val _level = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
-    override val level = _level
-
-    private val _numberOfLevels = MutableStateFlow(DEFAULT_NUM_LEVELS)
-    override val numberOfLevels = _numberOfLevels
-
     override val isForceHidden = MutableStateFlow(false)
 
     override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
 
-    fun setIsEmergencyOnly(emergency: Boolean) {
-        _isEmergencyOnly.value = emergency
-    }
+    override val signalLevelIcon: MutableStateFlow<SignalIconModel> =
+        MutableStateFlow(
+            SignalIconModel(
+                level = 0,
+                numberOfLevels = 4,
+                showExclamationMark = false,
+                carrierNetworkChange = false,
+            )
+        )
 
     fun setIsDataEnabled(enabled: Boolean) {
         _isDataEnabled.value = enabled
     }
-
-    fun setIsDefaultDataEnabled(disabled: Boolean) {
-        _isDefaultDataEnabled.value = disabled
-    }
-
-    fun setIsFailedConnection(failed: Boolean) {
-        _isFailedConnection.value = failed
-    }
-
-    fun setLevel(level: Int) {
-        _level.value = level
-    }
-
-    fun setNumberOfLevels(num: Int) {
-        _numberOfLevels.value = num
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 82b7ec4..75d1869 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -58,6 +58,8 @@
     private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false)
     override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled
 
+    override val activeDataIconInteractor = MutableStateFlow(null)
+
     override val alwaysShowDataRatIcon = MutableStateFlow(false)
 
     override val alwaysUseCdmaLevel = MutableStateFlow(false)
@@ -78,7 +80,7 @@
     override val isForceHidden = MutableStateFlow(false)
 
     /** Always returns a new fake interactor */
-    override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
+    override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor {
         return FakeMobileIconInteractor(tableLogBuffer).also { interactorCache[subId] = it }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index e3c59ad..e2f9119 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -35,6 +35,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G
 import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
@@ -75,22 +76,12 @@
     @Before
     fun setUp() {
         underTest = createInteractor()
+
+        mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
+        connectionRepository.isInService.value = true
     }
 
     @Test
-    fun gsm_level_default_unknown() =
-        testScope.runTest {
-            connectionRepository.isGsm.value = true
-
-            var latest: Int? = null
-            val job = underTest.level.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
-
-            job.cancel()
-        }
-
-    @Test
     fun gsm_usesGsmLevel() =
         testScope.runTest {
             connectionRepository.isGsm.value = true
@@ -98,7 +89,7 @@
             connectionRepository.cdmaLevel.value = CDMA_LEVEL
 
             var latest: Int? = null
-            val job = underTest.level.onEach { latest = it }.launchIn(this)
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
 
             assertThat(latest).isEqualTo(GSM_LEVEL)
 
@@ -114,7 +105,7 @@
             mobileIconsInteractor.alwaysUseCdmaLevel.value = true
 
             var latest: Int? = null
-            val job = underTest.level.onEach { latest = it }.launchIn(this)
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
 
             assertThat(latest).isEqualTo(GSM_LEVEL)
 
@@ -127,7 +118,7 @@
             connectionRepository.isGsm.value = false
 
             var latest: Int? = null
-            val job = underTest.level.onEach { latest = it }.launchIn(this)
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
 
             assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
             job.cancel()
@@ -142,7 +133,7 @@
             mobileIconsInteractor.alwaysUseCdmaLevel.value = true
 
             var latest: Int? = null
-            val job = underTest.level.onEach { latest = it }.launchIn(this)
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
 
             assertThat(latest).isEqualTo(CDMA_LEVEL)
 
@@ -158,7 +149,7 @@
             mobileIconsInteractor.alwaysUseCdmaLevel.value = false
 
             var latest: Int? = null
-            val job = underTest.level.onEach { latest = it }.launchIn(this)
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
 
             assertThat(latest).isEqualTo(GSM_LEVEL)
 
@@ -169,7 +160,7 @@
     fun numberOfLevels_comesFromRepo() =
         testScope.runTest {
             var latest: Int? = null
-            val job = underTest.numberOfLevels.onEach { latest = it }.launchIn(this)
+            val job = underTest.signalLevelIcon.onEach { latest = it.numberOfLevels }.launchIn(this)
 
             connectionRepository.numberOfLevels.value = 5
             assertThat(latest).isEqualTo(5)
@@ -295,50 +286,6 @@
         }
 
     @Test
-    fun alwaysUseCdmaLevel_matchesParent() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.alwaysUseCdmaLevel.onEach { latest = it }.launchIn(this)
-
-            mobileIconsInteractor.alwaysUseCdmaLevel.value = true
-            assertThat(latest).isTrue()
-
-            mobileIconsInteractor.alwaysUseCdmaLevel.value = false
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun test_isDefaultDataEnabled_matchesParent() =
-        testScope.runTest {
-            var latest: Boolean? = null
-            val job = underTest.isDefaultDataEnabled.onEach { latest = it }.launchIn(this)
-
-            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
-            assertThat(latest).isTrue()
-
-            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun test_isDefaultConnectionFailed_matchedParent() =
-        testScope.runTest {
-            val job = underTest.isDefaultConnectionFailed.launchIn(this)
-
-            mobileIconsInteractor.isDefaultConnectionFailed.value = false
-            assertThat(underTest.isDefaultConnectionFailed.value).isFalse()
-
-            mobileIconsInteractor.isDefaultConnectionFailed.value = true
-            assertThat(underTest.isDefaultConnectionFailed.value).isTrue()
-
-            job.cancel()
-        }
-
-    @Test
     fun dataState_connected() =
         testScope.runTest {
             var latest: Boolean? = null
@@ -541,6 +488,142 @@
             assertThat(latest).isFalse()
         }
 
+    @Test
+    fun iconId_correctLevel_notCutout() =
+        testScope.runTest {
+            connectionRepository.isInService.value = true
+            connectionRepository.primaryLevel.value = 1
+            connectionRepository.setDataEnabled(false)
+
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest?.level).isEqualTo(1)
+            assertThat(latest?.showExclamationMark).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_usesLevelFromInteractor() =
+        testScope.runTest {
+            connectionRepository.isInService.value = true
+
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.primaryLevel.value = 3
+            assertThat(latest!!.level).isEqualTo(3)
+
+            connectionRepository.primaryLevel.value = 1
+            assertThat(latest!!.level).isEqualTo(1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_usesNumberOfLevelsFromInteractor() =
+        testScope.runTest {
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.numberOfLevels.value = 5
+            assertThat(latest!!.numberOfLevels).isEqualTo(5)
+
+            connectionRepository.numberOfLevels.value = 2
+            assertThat(latest!!.numberOfLevels).isEqualTo(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_defaultDataDisabled_showExclamationTrue() =
+        testScope.runTest {
+            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
+
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest!!.showExclamationMark).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_defaultConnectionFailed_showExclamationTrue() =
+        testScope.runTest {
+            mobileIconsInteractor.isDefaultConnectionFailed.value = true
+
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest!!.showExclamationMark).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_enabledAndNotFailed_showExclamationFalse() =
+        testScope.runTest {
+            connectionRepository.isInService.value = true
+            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
+            mobileIconsInteractor.isDefaultConnectionFailed.value = false
+
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest!!.showExclamationMark).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_usesEmptyState_whenNotInService() =
+        testScope.runTest {
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.isInService.value = false
+
+            assertThat(latest?.level).isEqualTo(0)
+            assertThat(latest?.showExclamationMark).isTrue()
+
+            // Changing the level doesn't overwrite the disabled state
+            connectionRepository.primaryLevel.value = 2
+            assertThat(latest?.level).isEqualTo(0)
+            assertThat(latest?.showExclamationMark).isTrue()
+
+            // Once back in service, the regular icon appears
+            connectionRepository.isInService.value = true
+            assertThat(latest?.level).isEqualTo(2)
+            assertThat(latest?.showExclamationMark).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() =
+        testScope.runTest {
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.isInService.value = true
+            connectionRepository.carrierNetworkChangeActive.value = true
+            connectionRepository.primaryLevel.value = 1
+            connectionRepository.cdmaLevel.value = 1
+
+            assertThat(latest!!.level).isEqualTo(1)
+            assertThat(latest!!.carrierNetworkChange).isTrue()
+
+            // SignalIconModel respects the current level
+            connectionRepository.primaryLevel.value = 2
+
+            assertThat(latest!!.level).isEqualTo(2)
+            assertThat(latest!!.carrierNetworkChange).isTrue()
+
+            job.cancel()
+        }
+
     private fun createInteractor(
         overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
     ) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 3e6f909..b4c7578 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -781,6 +781,16 @@
             job.cancel()
         }
 
+    @Test
+    fun iconInteractor_cachedPerSubId() =
+        testScope.runTest {
+            val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+            val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+
+            assertThat(interactor1).isNotNull()
+            assertThat(interactor1).isSameInstanceAs(interactor2)
+        }
+
     /**
      * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions
      * flow.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
index 01c388a..90a8946 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/model/SignalIconModelParameterizedTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.filters.SmallTest
 import com.android.settingslib.graph.SignalDrawable
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index e59d90f..1878329 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -17,18 +17,26 @@
 package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
 
 import androidx.test.filters.SmallTest
-import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.connectivity.MobileIconCarrierIdOverridesFake
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
-import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
-import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
-import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModelTest.Companion.defaultSignal
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.CarrierConfigTracker
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,11 +58,18 @@
     private lateinit var homeIcon: HomeMobileIconViewModel
     private lateinit var qsIcon: QsMobileIconViewModel
     private lateinit var keyguardIcon: KeyguardMobileIconViewModel
-    private lateinit var interactor: FakeMobileIconInteractor
+    private lateinit var iconsInteractor: MobileIconsInteractor
+    private lateinit var interactor: MobileIconInteractor
+    private lateinit var connectionsRepository: FakeMobileConnectionsRepository
+    private lateinit var repository: FakeMobileConnectionRepository
     private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+
+    private val connectivityRepository = FakeConnectivityRepository()
+
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var constants: ConnectivityConstants
     @Mock private lateinit var tableLogBuffer: TableLogBuffer
+    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -67,16 +82,51 @@
                 FakeAirplaneModeRepository(),
                 FakeConnectivityRepository(),
             )
-        interactor = FakeMobileIconInteractor(tableLogBuffer)
-        interactor.apply {
-            setLevel(1)
-            setIsDefaultDataEnabled(true)
-            setIsFailedConnection(false)
-            setIsEmergencyOnly(false)
-            setNumberOfLevels(4)
-            networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
-            isDataConnected.value = true
-        }
+        connectionsRepository =
+            FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogBuffer)
+        repository =
+            FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer).apply {
+                isInService.value = true
+                cdmaLevel.value = 1
+                primaryLevel.value = 1
+                isEmergencyOnly.value = false
+                numberOfLevels.value = 4
+                resolvedNetworkType.value = ResolvedNetworkType.DefaultNetworkType(lookupKey = "3G")
+                dataConnectionState.value = DataConnectionState.Connected
+            }
+
+        connectionsRepository.activeMobileDataRepository.value = repository
+
+        connectivityRepository.apply { setMobileConnected() }
+
+        iconsInteractor =
+            MobileIconsInteractorImpl(
+                connectionsRepository,
+                carrierConfigTracker,
+                tableLogBuffer,
+                connectivityRepository,
+                FakeUserSetupRepository(),
+                testScope.backgroundScope,
+                context,
+            )
+
+        interactor =
+            MobileIconInteractorImpl(
+                testScope.backgroundScope,
+                iconsInteractor.activeDataConnectionHasDataEnabled,
+                iconsInteractor.alwaysShowDataRatIcon,
+                iconsInteractor.alwaysUseCdmaLevel,
+                iconsInteractor.isSingleCarrier,
+                iconsInteractor.mobileIsDefault,
+                iconsInteractor.defaultMobileIconMapping,
+                iconsInteractor.defaultMobileIconGroup,
+                iconsInteractor.isDefaultConnectionFailed,
+                iconsInteractor.isForceHidden,
+                repository,
+                context,
+                MobileIconCarrierIdOverridesFake()
+            )
+
         commonImpl =
             MobileIconViewModel(
                 SUB_1_ID,
@@ -109,7 +159,7 @@
             assertThat(latestQs).isEqualTo(expected)
             assertThat(latestKeyguard).isEqualTo(expected)
 
-            interactor.setLevel(2)
+            repository.setAllLevels(2)
             expected = defaultSignal(level = 2)
 
             assertThat(latestHome).isEqualTo(expected)
@@ -123,5 +173,16 @@
 
     companion object {
         private const val SUB_1_ID = 1
+        private const val NUM_LEVELS = 4
+
+        /** Convenience constructor for these tests */
+        fun defaultSignal(level: Int = 1): SignalIconModel {
+            return SignalIconModel(
+                level,
+                NUM_LEVELS,
+                showExclamationMark = false,
+                carrierNetworkChange = false,
+            )
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 72feec7..796d5ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -19,20 +19,30 @@
 import androidx.test.filters.SmallTest
 import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH
 import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.TelephonyIcons.G
 import com.android.settingslib.mobile.TelephonyIcons.THREE_G
 import com.android.settingslib.mobile.TelephonyIcons.UNKNOWN
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.connectivity.MobileIconCarrierIdOverridesFake
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
-import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
-import com.android.systemui.statusbar.pipeline.mobile.ui.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.util.CarrierConfigTracker
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -51,12 +61,18 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class MobileIconViewModelTest : SysuiTestCase() {
+    private var connectivityRepository = FakeConnectivityRepository()
+
     private lateinit var underTest: MobileIconViewModel
-    private lateinit var interactor: FakeMobileIconInteractor
+    private lateinit var interactor: MobileIconInteractorImpl
+    private lateinit var iconsInteractor: MobileIconsInteractorImpl
+    private lateinit var repository: FakeMobileConnectionRepository
+    private lateinit var connectionsRepository: FakeMobileConnectionsRepository
     private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
     private lateinit var airplaneModeInteractor: AirplaneModeInteractor
     @Mock private lateinit var constants: ConnectivityConstants
     @Mock private lateinit var tableLogBuffer: TableLogBuffer
+    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -66,23 +82,53 @@
         MockitoAnnotations.initMocks(this)
         whenever(constants.hasDataCapabilities).thenReturn(true)
 
+        connectionsRepository =
+            FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogBuffer)
+
+        repository =
+            FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer).apply {
+                setNetworkTypeKey(connectionsRepository.GSM_KEY)
+                isInService.value = true
+                dataConnectionState.value = DataConnectionState.Connected
+                dataEnabled.value = true
+            }
+        connectionsRepository.activeMobileDataRepository.value = repository
+        connectionsRepository.mobileIsDefault.value = true
+
         airplaneModeRepository = FakeAirplaneModeRepository()
         airplaneModeInteractor =
             AirplaneModeInteractor(
                 airplaneModeRepository,
-                FakeConnectivityRepository(),
+                connectivityRepository,
             )
 
-        interactor = FakeMobileIconInteractor(tableLogBuffer)
-        interactor.apply {
-            setLevel(1)
-            setIsDefaultDataEnabled(true)
-            setIsFailedConnection(false)
-            setIsEmergencyOnly(false)
-            setNumberOfLevels(4)
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            isDataConnected.value = true
-        }
+        iconsInteractor =
+            MobileIconsInteractorImpl(
+                connectionsRepository,
+                carrierConfigTracker,
+                tableLogBuffer,
+                connectivityRepository,
+                FakeUserSetupRepository(),
+                testScope.backgroundScope,
+                context,
+            )
+
+        interactor =
+            MobileIconInteractorImpl(
+                testScope.backgroundScope,
+                iconsInteractor.activeDataConnectionHasDataEnabled,
+                iconsInteractor.alwaysShowDataRatIcon,
+                iconsInteractor.alwaysUseCdmaLevel,
+                iconsInteractor.isSingleCarrier,
+                iconsInteractor.mobileIsDefault,
+                iconsInteractor.defaultMobileIconMapping,
+                iconsInteractor.defaultMobileIconGroup,
+                iconsInteractor.isDefaultConnectionFailed,
+                iconsInteractor.isForceHidden,
+                repository,
+                context,
+                MobileIconCarrierIdOverridesFake()
+            )
         createAndSetViewModel()
     }
 
@@ -108,7 +154,6 @@
             val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
 
             airplaneModeRepository.setIsAirplaneMode(false)
-            interactor.isForceHidden.value = false
 
             assertThat(latest).isTrue()
 
@@ -122,8 +167,8 @@
             val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
 
             airplaneModeRepository.setIsAirplaneMode(true)
-            interactor.isAllowedDuringAirplaneMode.value = false
-            interactor.isForceHidden.value = false
+            repository.isAllowedDuringAirplaneMode.value = false
+            connectivityRepository.setForceHiddenIcons(setOf())
 
             assertThat(latest).isFalse()
 
@@ -138,8 +183,8 @@
             val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
 
             airplaneModeRepository.setIsAirplaneMode(true)
-            interactor.isAllowedDuringAirplaneMode.value = true
-            interactor.isForceHidden.value = false
+            repository.isAllowedDuringAirplaneMode.value = true
+            connectivityRepository.setForceHiddenIcons(setOf())
 
             assertThat(latest).isTrue()
 
@@ -153,7 +198,7 @@
             val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
 
             airplaneModeRepository.setIsAirplaneMode(false)
-            interactor.isForceHidden.value = true
+            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
 
             assertThat(latest).isFalse()
 
@@ -167,156 +212,29 @@
             val job = underTest.isVisible.onEach { latest = it }.launchIn(this)
 
             airplaneModeRepository.setIsAirplaneMode(false)
-            interactor.isForceHidden.value = false
+            connectivityRepository.setForceHiddenIcons(setOf())
 
             assertThat(latest).isTrue()
 
             airplaneModeRepository.setIsAirplaneMode(true)
             assertThat(latest).isFalse()
 
-            interactor.isAllowedDuringAirplaneMode.value = true
+            repository.isAllowedDuringAirplaneMode.value = true
             assertThat(latest).isTrue()
 
-            interactor.isForceHidden.value = true
+            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
             assertThat(latest).isFalse()
 
             job.cancel()
         }
 
     @Test
-    fun iconId_correctLevel_notCutout() =
-        testScope.runTest {
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-            val expected = defaultSignal()
-
-            assertThat(latest).isEqualTo(expected)
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_usesLevelFromInteractor() =
-        testScope.runTest {
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            interactor.level.value = 3
-            assertThat(latest!!.level).isEqualTo(3)
-
-            interactor.level.value = 1
-            assertThat(latest!!.level).isEqualTo(1)
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_usesNumberOfLevelsFromInteractor() =
-        testScope.runTest {
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            interactor.numberOfLevels.value = 5
-            assertThat(latest!!.numberOfLevels).isEqualTo(5)
-
-            interactor.numberOfLevels.value = 2
-            assertThat(latest!!.numberOfLevels).isEqualTo(2)
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_defaultDataDisabled_showExclamationTrue() =
-        testScope.runTest {
-            interactor.setIsDefaultDataEnabled(false)
-
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest!!.showExclamationMark).isTrue()
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_defaultConnectionFailed_showExclamationTrue() =
-        testScope.runTest {
-            interactor.isDefaultConnectionFailed.value = true
-
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest!!.showExclamationMark).isTrue()
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_enabledAndNotFailed_showExclamationFalse() =
-        testScope.runTest {
-            interactor.setIsDefaultDataEnabled(true)
-            interactor.isDefaultConnectionFailed.value = false
-
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest!!.showExclamationMark).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_usesEmptyState_whenNotInService() =
-        testScope.runTest {
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            interactor.isInService.value = false
-
-            var expected = emptySignal()
-
-            assertThat(latest).isEqualTo(expected)
-
-            // Changing the level doesn't overwrite the disabled state
-            interactor.level.value = 2
-            assertThat(latest).isEqualTo(expected)
-
-            // Once back in service, the regular icon appears
-            interactor.isInService.value = true
-            expected = defaultSignal(level = 2)
-            assertThat(latest).isEqualTo(expected)
-
-            job.cancel()
-        }
-
-    @Test
-    fun icon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() =
-        testScope.runTest {
-            var latest: SignalIconModel? = null
-            val job = underTest.icon.onEach { latest = it }.launchIn(this)
-
-            interactor.carrierNetworkChangeActive.value = true
-            interactor.level.value = 1
-
-            assertThat(latest!!.level).isEqualTo(1)
-            assertThat(latest!!.carrierNetworkChange).isTrue()
-
-            // SignalIconModel respects the current level
-            interactor.level.value = 2
-
-            assertThat(latest!!.level).isEqualTo(2)
-            assertThat(latest!!.carrierNetworkChange).isTrue()
-
-            job.cancel()
-        }
-
-    @Test
     fun contentDescription_notInService_usesNoPhone() =
         testScope.runTest {
             var latest: ContentDescription? = null
             val job = underTest.contentDescription.onEach { latest = it }.launchIn(this)
 
-            interactor.isInService.value = false
+            repository.isInService.value = false
 
             assertThat((latest as ContentDescription.Resource).res)
                 .isEqualTo(PHONE_SIGNAL_STRENGTH_NONE)
@@ -330,13 +248,11 @@
             var latest: ContentDescription? = null
             val job = underTest.contentDescription.onEach { latest = it }.launchIn(this)
 
-            interactor.isInService.value = true
-
-            interactor.level.value = 2
+            repository.setAllLevels(2)
             assertThat((latest as ContentDescription.Resource).res)
                 .isEqualTo(PHONE_SIGNAL_STRENGTH[2])
 
-            interactor.level.value = 0
+            repository.setAllLevels(0)
             assertThat((latest as ContentDescription.Resource).res)
                 .isEqualTo(PHONE_SIGNAL_STRENGTH[0])
 
@@ -351,7 +267,8 @@
                     THREE_G.dataType,
                     ContentDescription.Resource(THREE_G.dataContentDescription)
                 )
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
+            connectionsRepository.mobileIsDefault.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
@@ -364,9 +281,9 @@
     @Test
     fun networkType_null_whenDisabled() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.setIsDataEnabled(false)
-            interactor.mobileIsDefault.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.setDataEnabled(false)
+            connectionsRepository.mobileIsDefault.value = true
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
 
@@ -378,9 +295,9 @@
     @Test
     fun networkType_null_whenCarrierNetworkChangeActive() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.carrierNetworkChangeActive.value = true
-            interactor.mobileIsDefault.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.carrierNetworkChangeActive.value = true
+            connectionsRepository.mobileIsDefault.value = true
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
 
@@ -397,10 +314,10 @@
                     THREE_G.dataType,
                     ContentDescription.Resource(THREE_G.dataContentDescription)
                 )
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.setIsDataEnabled(true)
-            interactor.isDataConnected.value = true
-            interactor.mobileIsDefault.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.setDataEnabled(true)
+            repository.dataConnectionState.value = DataConnectionState.Connected
+            connectionsRepository.mobileIsDefault.value = true
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
 
@@ -418,15 +335,13 @@
                     ContentDescription.Resource(THREE_G.dataContentDescription)
                 )
 
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
 
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
             assertThat(latest).isEqualTo(initial)
 
-            interactor.isDataConnected.value = false
-            yield()
+            repository.dataConnectionState.value = DataConnectionState.Disconnected
 
             assertThat(latest).isNull()
 
@@ -441,15 +356,13 @@
                     THREE_G.dataType,
                     ContentDescription.Resource(THREE_G.dataContentDescription)
                 )
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.setIsDataEnabled(true)
+            repository.dataEnabled.value = true
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
 
             assertThat(latest).isEqualTo(expected)
 
-            interactor.setIsDataEnabled(false)
-            yield()
+            repository.dataEnabled.value = false
 
             assertThat(latest).isNull()
 
@@ -459,9 +372,10 @@
     @Test
     fun networkType_alwaysShow_shownEvenWhenDisabled() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.setIsDataEnabled(false)
-            interactor.alwaysShowDataRatIcon.value = true
+            repository.dataEnabled.value = false
+
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
@@ -479,9 +393,11 @@
     @Test
     fun networkType_alwaysShow_shownEvenWhenDisconnected() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.isDataConnected.value = false
-            interactor.alwaysShowDataRatIcon.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.dataConnectionState.value = DataConnectionState.Disconnected
+
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
@@ -499,9 +415,10 @@
     @Test
     fun networkType_alwaysShow_shownEvenWhenFailedConnection() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.setIsFailedConnection(true)
-            interactor.alwaysShowDataRatIcon.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
@@ -517,16 +434,24 @@
         }
 
     @Test
-    fun networkType_alwaysShow_notShownWhenInvalidDataTypeIcon() =
+    fun networkType_alwaysShow_usesDefaultIconWhenInvalid() =
         testScope.runTest {
-            // The UNKNOWN icon group doesn't have a valid data type icon ID
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(UNKNOWN)
-            interactor.alwaysShowDataRatIcon.value = true
+            // The UNKNOWN icon group doesn't have a valid data type icon ID, and the logic from the
+            // old pipeline was to use the default icon group if the map doesn't exist
+            repository.setNetworkTypeKey(UNKNOWN.name)
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
 
-            assertThat(latest).isNull()
+            val expected =
+                Icon.Resource(
+                    connectionsRepository.defaultMobileIconGroup.value.dataType,
+                    ContentDescription.Resource(G.dataContentDescription)
+                )
+
+            assertThat(latest).isEqualTo(expected)
 
             job.cancel()
         }
@@ -534,9 +459,10 @@
     @Test
     fun networkType_alwaysShow_shownWhenNotDefault() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.mobileIsDefault.value = false
-            interactor.alwaysShowDataRatIcon.value = true
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            connectionsRepository.mobileIsDefault.value = false
+            connectionsRepository.defaultDataSubRatConfig.value =
+                MobileMappings.Config().also { it.alwaysShowDataRatIcon = true }
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
@@ -554,9 +480,9 @@
     @Test
     fun networkType_notShownWhenNotDefault() =
         testScope.runTest {
-            interactor.networkTypeIconGroup.value = NetworkTypeIconModel.DefaultIcon(THREE_G)
-            interactor.isDataConnected.value = true
-            interactor.mobileIsDefault.value = false
+            repository.setNetworkTypeKey(connectionsRepository.GSM_KEY)
+            repository.dataConnectionState.value = DataConnectionState.Connected
+            connectionsRepository.mobileIsDefault.value = false
 
             var latest: Icon? = null
             val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
@@ -569,13 +495,14 @@
     @Test
     fun roaming() =
         testScope.runTest {
-            interactor.isRoaming.value = true
+            repository.setAllRoaming(true)
+
             var latest: Boolean? = null
             val job = underTest.roaming.onEach { latest = it }.launchIn(this)
 
             assertThat(latest).isTrue()
 
-            interactor.isRoaming.value = false
+            repository.setAllRoaming(false)
 
             assertThat(latest).isFalse()
 
@@ -599,7 +526,7 @@
             val containerJob =
                 underTest.activityInVisible.onEach { containerVisible = it }.launchIn(this)
 
-            interactor.activity.value =
+            repository.dataActivityDirection.value =
                 DataActivityModel(
                     hasActivityIn = true,
                     hasActivityOut = true,
@@ -631,7 +558,7 @@
             val containerJob =
                 underTest.activityContainerVisible.onEach { containerVisible = it }.launchIn(this)
 
-            interactor.activity.value =
+            repository.dataActivityDirection.value =
                 DataActivityModel(
                     hasActivityIn = true,
                     hasActivityOut = false,
@@ -643,7 +570,7 @@
             assertThat(outVisible).isFalse()
             assertThat(containerVisible).isTrue()
 
-            interactor.activity.value =
+            repository.dataActivityDirection.value =
                 DataActivityModel(
                     hasActivityIn = false,
                     hasActivityOut = true,
@@ -653,7 +580,7 @@
             assertThat(outVisible).isTrue()
             assertThat(containerVisible).isTrue()
 
-            interactor.activity.value =
+            repository.dataActivityDirection.value =
                 DataActivityModel(
                     hasActivityIn = false,
                     hasActivityOut = false,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index 065dfba..eb6f2f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -78,7 +78,6 @@
                 airplaneModeInteractor,
                 constants,
                 testScope.backgroundScope,
-                statusBarPipelineFlags,
             )
 
         interactor.filteredSubscriptions.value = listOf(SUB_1, SUB_2)
@@ -154,33 +153,6 @@
         }
 
     @Test
-    fun caching_mobileIconInteractorIsReusedForSameSubId() =
-        testScope.runTest {
-            val interactor1 = underTest.mobileIconInteractorForSub(1)
-            val interactor2 = underTest.mobileIconInteractorForSub(1)
-
-            assertThat(interactor1).isSameInstanceAs(interactor2)
-        }
-
-    @Test
-    fun caching_invalidInteractorssAreRemovedFromCacheWhenSubDisappears() =
-        testScope.runTest {
-            // Retrieve interactors to trigger caching
-            val interactor1 = underTest.mobileIconInteractorForSub(1)
-            val interactor2 = underTest.mobileIconInteractorForSub(2)
-
-            // Both impls are cached
-            assertThat(underTest.mobileIconInteractorSubIdCache)
-                .containsExactly(1, interactor1, 2, interactor2)
-
-            // SUB_1 is removed from the list...
-            interactor.filteredSubscriptions.value = listOf(SUB_2)
-
-            // ... and dropped from the cache
-            assertThat(underTest.mobileIconInteractorSubIdCache).containsExactly(2, interactor2)
-        }
-
-    @Test
     fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() =
         testScope.runTest {
             var latest: Boolean? = null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
index 8f28cc0..e44ff8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt
@@ -27,7 +27,7 @@
         MutableStateFlow(emptySet())
     override val forceHiddenSlots: StateFlow<Set<ConnectivitySlot>> = _forceHiddenIcons
 
-    override val defaultConnections: StateFlow<DefaultConnectionModel> =
+    override val defaultConnections: MutableStateFlow<DefaultConnectionModel> =
         MutableStateFlow(DefaultConnectionModel())
 
     override val vcnSubId: MutableStateFlow<Int?> = MutableStateFlow(null)
@@ -35,4 +35,43 @@
     fun setForceHiddenIcons(hiddenIcons: Set<ConnectivitySlot>) {
         _forceHiddenIcons.value = hiddenIcons
     }
+
+    /**
+     * Convenience for setting mobile data connected, disconnected, or validated. Defaults to
+     * setting mobile connected && validated, since the default state is disconnected && not
+     * validated
+     */
+    fun setMobileConnected(
+        default: Boolean = true,
+        validated: Boolean = true,
+    ) {
+        defaultConnections.value =
+            DefaultConnectionModel(
+                mobile = DefaultConnectionModel.Mobile(default),
+                isValidated = validated,
+            )
+    }
+
+    /** Similar convenience method for ethernet */
+    fun setEthernetConnected(
+        default: Boolean = true,
+        validated: Boolean = true,
+    ) {
+        defaultConnections.value =
+            DefaultConnectionModel(
+                ethernet = DefaultConnectionModel.Ethernet(default),
+                isValidated = validated,
+            )
+    }
+
+    fun setWifiConnected(
+        default: Boolean = true,
+        validated: Boolean = true,
+    ) {
+        defaultConnections.value =
+            DefaultConnectionModel(
+                wifi = DefaultConnectionModel.Wifi(default),
+                isValidated = validated,
+            )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
new file mode 100644
index 0000000..6624ec2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
+import com.android.systemui.statusbar.connectivity.WifiIcons
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.ethernet.domain.EthernetInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.ui.model.SignalIcon
+import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.InternetTileViewModel.Companion.NOT_CONNECTED_NETWORKS_UNAVAILABLE
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class InternetTileViewModelTest : SysuiTestCase() {
+    private lateinit var underTest: InternetTileViewModel
+    private lateinit var mobileIconsInteractor: MobileIconsInteractor
+
+    private val airplaneModeRepository = FakeAirplaneModeRepository()
+    private val connectivityRepository = FakeConnectivityRepository()
+    private val ethernetInteractor = EthernetInteractor(connectivityRepository)
+    private val wifiRepository = FakeWifiRepository()
+    private val userSetupRepo = FakeUserSetupRepository()
+    private val testScope = TestScope()
+    private val wifiInteractor =
+        WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope)
+
+    private val tableLogBuffer: TableLogBuffer = mock()
+    private val carrierConfigTracker: CarrierConfigTracker = mock()
+
+    private val mobileConnectionsRepository =
+        FakeMobileConnectionsRepository(FakeMobileMappingsProxy(), tableLogBuffer)
+    private val mobileConnectionRepository =
+        FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer)
+
+    @Before
+    fun setUp() {
+        mobileConnectionRepository.apply {
+            setNetworkTypeKey(mobileConnectionsRepository.GSM_KEY)
+            isInService.value = true
+            dataConnectionState.value = DataConnectionState.Connected
+            dataEnabled.value = true
+        }
+
+        mobileConnectionsRepository.apply {
+            activeMobileDataRepository.value = mobileConnectionRepository
+            activeMobileDataSubscriptionId.value = SUB_1_ID
+            setMobileConnectionRepositoryMap(mapOf(SUB_1_ID to mobileConnectionRepository))
+        }
+
+        mobileIconsInteractor =
+            MobileIconsInteractorImpl(
+                mobileConnectionsRepository,
+                carrierConfigTracker,
+                tableLogBuffer,
+                connectivityRepository,
+                userSetupRepo,
+                testScope.backgroundScope,
+                context,
+            )
+
+        underTest =
+            InternetTileViewModel(
+                airplaneModeRepository,
+                connectivityRepository,
+                ethernetInteractor,
+                mobileIconsInteractor,
+                wifiInteractor,
+                context,
+                testScope.backgroundScope,
+            )
+    }
+
+    @Test
+    fun noDefault_noNetworksAvailable() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            connectivityRepository.defaultConnections.value = DefaultConnectionModel()
+
+            assertThat(latest?.secondaryLabel)
+                .isEqualTo(Text.Resource(R.string.quick_settings_networks_unavailable))
+            assertThat(latest?.iconId).isEqualTo(R.drawable.ic_qs_no_internet_unavailable)
+        }
+
+    @Test
+    fun noDefault_networksAvailable() =
+        testScope.runTest {
+            // TODO: support [WifiInteractor.areNetworksAvailable]
+        }
+
+    @Test
+    fun wifiDefaultAndActive() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            val networkModel =
+                WifiNetworkModel.Active(
+                    networkId = 1,
+                    level = 4,
+                    ssid = "test ssid",
+                )
+
+            connectivityRepository.setWifiConnected()
+            wifiRepository.setIsWifiDefault(true)
+            wifiRepository.setWifiNetwork(networkModel)
+
+            assertThat(latest?.secondaryTitle).isEqualTo("test ssid")
+            assertThat(latest?.secondaryLabel).isNull()
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(WifiIcons.WIFI_NO_INTERNET_ICONS[4]))
+            assertThat(latest?.iconId).isNull()
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotNone() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            val networkModel =
+                WifiNetworkModel.Active(
+                    networkId = 1,
+                    level = 4,
+                    ssid = "test ssid",
+                    hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.NONE,
+                )
+
+            connectivityRepository.setWifiConnected()
+            wifiRepository.setIsWifiDefault(true)
+            wifiRepository.setWifiNetwork(networkModel)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(WifiIcons.WIFI_NO_INTERNET_ICONS[4]))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotTablet() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.TABLET)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_tablet))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotLaptop() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.LAPTOP)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_laptop))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotWatch() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.WATCH)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_watch))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotAuto() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.AUTO)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_auto))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotPhone() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.PHONE)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_phone))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotUnknown() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.UNKNOWN)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_phone))
+        }
+
+    @Test
+    fun wifiDefaultAndActive_hotspotInvalid() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            setWifiNetworkWithHotspot(WifiNetworkModel.HotspotDeviceType.INVALID)
+
+            assertThat(latest?.icon)
+                .isEqualTo(ResourceIcon.get(com.android.settingslib.R.drawable.ic_hotspot_phone))
+        }
+
+    @Test
+    fun wifiDefaultAndNotActive_noNetworksAvailable() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            val networkModel = WifiNetworkModel.Inactive
+
+            connectivityRepository.setWifiConnected(validated = false)
+            wifiRepository.setIsWifiDefault(true)
+            wifiRepository.setWifiNetwork(networkModel)
+            wifiRepository.wifiScanResults.value = emptyList()
+
+            assertThat(latest).isEqualTo(NOT_CONNECTED_NETWORKS_UNAVAILABLE)
+        }
+
+    @Test
+    fun wifiDefaultAndNotActive_networksAvailable() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            val networkModel = WifiNetworkModel.Inactive
+
+            connectivityRepository.setWifiConnected(validated = false)
+            wifiRepository.setIsWifiDefault(true)
+            wifiRepository.setWifiNetwork(networkModel)
+            wifiRepository.wifiScanResults.value = listOf(WifiScanEntry("test 1"))
+
+            assertThat(latest?.secondaryLabel).isNull()
+            assertThat(latest?.secondaryTitle)
+                .isEqualTo(context.getString(R.string.quick_settings_networks_available))
+            assertThat(latest?.icon).isNull()
+            assertThat(latest?.iconId).isEqualTo(R.drawable.ic_qs_no_internet_available)
+        }
+
+    @Test
+    fun mobileDefault_usesNetworkNameAndIcon() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+
+            connectivityRepository.setMobileConnected()
+            mobileConnectionsRepository.mobileIsDefault.value = true
+            mobileConnectionRepository.apply {
+                setAllLevels(3)
+                setAllRoaming(false)
+                networkName.value = NetworkNameModel.Default("test network")
+            }
+
+            assertThat(latest?.secondaryTitle).contains("test network")
+            assertThat(latest?.secondaryLabel).isNull()
+            assertThat(latest?.icon).isInstanceOf(SignalIcon::class.java)
+            assertThat(latest?.iconId).isNull()
+        }
+
+    @Test
+    fun ethernetDefault_validated_matchesInteractor() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+            val ethernetIcon by collectLastValue(ethernetInteractor.icon)
+
+            connectivityRepository.setEthernetConnected(default = true, validated = true)
+
+            assertThat(latest?.secondaryLabel).isNull()
+            assertThat(latest?.secondaryTitle)
+                .isEqualTo(ethernetIcon!!.contentDescription.toString())
+            assertThat(latest?.iconId).isEqualTo(R.drawable.stat_sys_ethernet_fully)
+            assertThat(latest?.icon).isNull()
+        }
+
+    @Test
+    fun ethernetDefault_notValidated_matchesInteractor() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.tileModel)
+            val ethernetIcon by collectLastValue(ethernetInteractor.icon)
+
+            connectivityRepository.setEthernetConnected(default = true, validated = false)
+
+            assertThat(latest?.secondaryLabel).isNull()
+            assertThat(latest?.secondaryTitle)
+                .isEqualTo(ethernetIcon!!.contentDescription.toString())
+            assertThat(latest?.iconId).isEqualTo(R.drawable.stat_sys_ethernet)
+            assertThat(latest?.icon).isNull()
+        }
+
+    private fun setWifiNetworkWithHotspot(hotspot: WifiNetworkModel.HotspotDeviceType) {
+        val networkModel =
+            WifiNetworkModel.Active(
+                networkId = 1,
+                level = 4,
+                ssid = "test ssid",
+                hotspotDeviceType = hotspot,
+            )
+
+        connectivityRepository.setWifiConnected()
+        wifiRepository.setIsWifiDefault(true)
+        wifiRepository.setWifiNetwork(networkModel)
+    }
+
+    companion object {
+        const val SUB_1_ID = 1
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index 4f7bb72..106b548 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryHelper.ACTIVITY_DEFAULT
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 
@@ -39,6 +40,9 @@
     private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
     override val wifiActivity: StateFlow<DataActivityModel> = _wifiActivity
 
+    override val wifiScanResults: MutableStateFlow<List<WifiScanEntry>> =
+        MutableStateFlow(emptyList())
+
     fun setIsWifiEnabled(enabled: Boolean) {
         _isWifiEnabled.value = enabled
     }
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 bea1154..c2e75aa 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
@@ -27,6 +27,7 @@
 import android.net.TransportInfo
 import android.net.VpnTransportInfo
 import android.net.vcn.VcnTransportInfo
+import android.net.wifi.ScanResult
 import android.net.wifi.WifiInfo
 import android.net.wifi.WifiManager
 import android.net.wifi.WifiManager.TrafficStateCallback
@@ -45,6 +46,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiInputLogger
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
@@ -1205,6 +1207,58 @@
                 .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
         }
 
+    @Test
+    fun wifiScanResults_containsSsidList() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.wifiScanResults)
+
+            val scanResults =
+                listOf(
+                    ScanResult().also { it.SSID = "ssid 1" },
+                    ScanResult().also { it.SSID = "ssid 2" },
+                    ScanResult().also { it.SSID = "ssid 3" },
+                    ScanResult().also { it.SSID = "ssid 4" },
+                    ScanResult().also { it.SSID = "ssid 5" },
+                )
+            whenever(wifiManager.scanResults).thenReturn(scanResults)
+            getScanResultsCallback().onScanResultsAvailable()
+
+            val expected =
+                listOf(
+                    WifiScanEntry(ssid = "ssid 1"),
+                    WifiScanEntry(ssid = "ssid 2"),
+                    WifiScanEntry(ssid = "ssid 3"),
+                    WifiScanEntry(ssid = "ssid 4"),
+                    WifiScanEntry(ssid = "ssid 5"),
+                )
+
+            assertThat(latest).isEqualTo(expected)
+        }
+
+    @Test
+    fun wifiScanResults_updates() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.wifiScanResults)
+
+            var scanResults =
+                listOf(
+                    ScanResult().also { it.SSID = "ssid 1" },
+                    ScanResult().also { it.SSID = "ssid 2" },
+                    ScanResult().also { it.SSID = "ssid 3" },
+                    ScanResult().also { it.SSID = "ssid 4" },
+                    ScanResult().also { it.SSID = "ssid 5" },
+                )
+            whenever(wifiManager.scanResults).thenReturn(scanResults)
+            getScanResultsCallback().onScanResultsAvailable()
+
+            // New scan representing no results
+            scanResults = emptyList()
+            whenever(wifiManager.scanResults).thenReturn(scanResults)
+            getScanResultsCallback().onScanResultsAvailable()
+
+            assertThat(latest).isEmpty()
+        }
+
     private fun createRepo(): WifiRepositoryImpl {
         return WifiRepositoryImpl(
             fakeBroadcastDispatcher,
@@ -1240,6 +1294,13 @@
         return callbackCaptor.value!!
     }
 
+    private fun getScanResultsCallback(): WifiManager.ScanResultsCallback {
+        testScope.runCurrent()
+        val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>()
+        verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture())
+        return callbackCaptor.value!!
+    }
+
     private fun createWifiNetworkCapabilities(
         transportInfo: TransportInfo,
         isValidated: Boolean = true,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
index 662e36a..afab623 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryViaTrackerLibTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.data.repository.prod
 
+import android.net.wifi.ScanResult
 import android.net.wifi.WifiManager
 import android.net.wifi.WifiManager.UNKNOWN_SSID
 import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
@@ -32,6 +33,7 @@
 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.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
@@ -77,6 +79,7 @@
             featureFlags,
             testScope.backgroundScope,
             executor,
+            dispatcher,
             wifiPickerTrackerFactory,
             wifiManager,
             logger,
@@ -1137,6 +1140,58 @@
                 .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
         }
 
+    @Test
+    fun wifiScanResults_containsSsidList() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.wifiScanResults)
+
+            val scanResults =
+                listOf(
+                    ScanResult().also { it.SSID = "ssid 1" },
+                    ScanResult().also { it.SSID = "ssid 2" },
+                    ScanResult().also { it.SSID = "ssid 3" },
+                    ScanResult().also { it.SSID = "ssid 4" },
+                    ScanResult().also { it.SSID = "ssid 5" },
+                )
+            whenever(wifiManager.scanResults).thenReturn(scanResults)
+            getScanResultsCallback().onScanResultsAvailable()
+
+            val expected =
+                listOf(
+                    WifiScanEntry(ssid = "ssid 1"),
+                    WifiScanEntry(ssid = "ssid 2"),
+                    WifiScanEntry(ssid = "ssid 3"),
+                    WifiScanEntry(ssid = "ssid 4"),
+                    WifiScanEntry(ssid = "ssid 5"),
+                )
+
+            assertThat(latest).isEqualTo(expected)
+        }
+
+    @Test
+    fun wifiScanResults_updates() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.wifiScanResults)
+
+            var scanResults =
+                listOf(
+                    ScanResult().also { it.SSID = "ssid 1" },
+                    ScanResult().also { it.SSID = "ssid 2" },
+                    ScanResult().also { it.SSID = "ssid 3" },
+                    ScanResult().also { it.SSID = "ssid 4" },
+                    ScanResult().also { it.SSID = "ssid 5" },
+                )
+            whenever(wifiManager.scanResults).thenReturn(scanResults)
+            getScanResultsCallback().onScanResultsAvailable()
+
+            // New scan representing no results
+            scanResults = listOf()
+            whenever(wifiManager.scanResults).thenReturn(scanResults)
+            getScanResultsCallback().onScanResultsAvailable()
+
+            assertThat(latest).isEmpty()
+        }
+
     private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback {
         testScope.runCurrent()
         return callbackCaptor.value
@@ -1156,6 +1211,13 @@
         }
     }
 
+    private fun getScanResultsCallback(): WifiManager.ScanResultsCallback {
+        testScope.runCurrent()
+        val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>()
+        verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture())
+        return callbackCaptor.value!!
+    }
+
     private companion object {
         const val TITLE = "AB"
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
index 6fe88c1..1db8065 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
@@ -21,11 +21,13 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.launchIn
@@ -56,7 +58,8 @@
     fun setUp() {
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
-        underTest = WifiInteractorImpl(connectivityRepository, wifiRepository)
+        underTest =
+            WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope)
     }
 
     @Test
@@ -300,4 +303,76 @@
 
             job.cancel()
         }
+
+    @Test
+    fun areNetworksAvailable_noneActive_noResults() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areNetworksAvailable)
+
+            wifiRepository.wifiScanResults.value = emptyList()
+            wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun areNetworksAvailable_noneActive_nonEmptyResults() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areNetworksAvailable)
+
+            wifiRepository.wifiScanResults.value =
+                listOf(
+                    WifiScanEntry(ssid = "ssid 1"),
+                    WifiScanEntry(ssid = "ssid 2"),
+                    WifiScanEntry(ssid = "ssid 3"),
+                )
+
+            wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun areNetworksAvailable_activeNetwork_resultsIncludeOtherNetworks() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areNetworksAvailable)
+
+            wifiRepository.wifiScanResults.value =
+                listOf(
+                    WifiScanEntry(ssid = "ssid 1"),
+                    WifiScanEntry(ssid = "ssid 2"),
+                    WifiScanEntry(ssid = "ssid 3"),
+                )
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.Active(
+                    ssid = "ssid 2",
+                    networkId = 1,
+                    level = 2,
+                )
+            )
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun areNetworksAvailable_activeNetwork_onlyResultIsTheActiveNetwork() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areNetworksAvailable)
+
+            wifiRepository.wifiScanResults.value =
+                listOf(
+                    WifiScanEntry(ssid = "ssid 2"),
+                )
+
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.Active(
+                    ssid = "ssid 2",
+                    networkId = 1,
+                    level = 2,
+                )
+            )
+
+            assertThat(latest).isFalse()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 3f49935..a0d4d13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -82,8 +82,8 @@
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
         wifiRepository.setIsWifiEnabled(true)
-        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository)
         scope = CoroutineScope(Dispatchers.Unconfined)
+        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository, scope)
         airplaneModeViewModel =
             AirplaneModeViewModelImpl(
                 AirplaneModeInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index e6724d8..1d1b84c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -40,7 +40,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
-import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
+import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon.Companion.NO_INTERNET
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -83,8 +83,8 @@
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
         wifiRepository.setIsWifiEnabled(true)
-        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository)
         scope = CoroutineScope(IMMEDIATE)
+        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository, scope)
         airplaneModeViewModel =
             AirplaneModeViewModelImpl(
                 AirplaneModeInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index bdeba2a..a520f6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.connectivity.WifiIcons
 import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
@@ -74,7 +75,8 @@
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
         wifiRepository.setIsWifiEnabled(true)
-        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository)
+        interactor =
+            WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope)
         airplaneModeViewModel =
             AirplaneModeViewModelImpl(
                 AirplaneModeInteractor(
@@ -116,6 +118,27 @@
         }
 
     @Test
+    fun wifiIcon_validHotspot_hotspotIconNotShown() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.wifiIcon)
+
+            // Even WHEN the network has a valid hotspot type
+            wifiRepository.setWifiNetwork(
+                WifiNetworkModel.Active(
+                    NETWORK_ID,
+                    isValidated = true,
+                    level = 1,
+                    hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.LAPTOP,
+                )
+            )
+
+            // THEN the hotspot icon is not used for the status bar icon, and the typical wifi icon
+            // is used instead
+            assertThat(latest).isInstanceOf(WifiIcon.Visible::class.java)
+            assertThat((latest as WifiIcon.Visible).res).isEqualTo(WifiIcons.WIFI_FULL_ICONS[1])
+        }
+
+    @Test
     fun activity_showActivityConfigFalse_outputsFalse() =
         testScope.runTest {
             whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false)
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt
similarity index 67%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt
index 24064b1..274acc9 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt
@@ -11,16 +11,12 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
 
-package com.android.systemui.scene.ui.composable
+package com.android.systemui.util.kotlin
 
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
+import kotlinx.coroutines.flow.MutableStateFlow
 
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
-}
+/** Wrapper for flow constructors that can be retrieved from java tests */
+fun <T> getMutableStateFlow(value: T): MutableStateFlow<T> = MutableStateFlow(value)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index c12df98..65cac6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -57,6 +57,7 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -71,6 +72,7 @@
 
 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;
@@ -82,7 +84,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class VolumeDialogImplTest extends SysuiTestCase {
     VolumeDialogImpl mDialog;
     View mActiveRinger;
@@ -129,6 +131,9 @@
     private FakeFeatureFlags mFeatureFlags;
     private int mLongestHideShowAnimationDuration = 250;
 
+    @Rule
+    public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+
     @Before
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -136,6 +141,7 @@
         getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
 
         mTestableLooper = TestableLooper.get(this);
+        allowTestableLooperAsMainThread();
 
         when(mPostureController.getDevicePosture())
                 .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
@@ -242,7 +248,6 @@
                 | AccessibilityManager.FLAG_CONTENT_TEXT);
     }
 
-
     @Test
     public void testComputeTimeout_withHovering() {
         Mockito.reset(mAccessibilityMgr);
@@ -669,11 +674,12 @@
 
     @After
     public void teardown() {
-        cleanUp(mDialog);
         setOrientation(mOriginalOrientation);
+        mAnimatorTestRule.advanceTimeBy(mLongestHideShowAnimationDuration);
         mTestableLooper.moveTimeForward(mLongestHideShowAnimationDuration);
         mTestableLooper.processAllMessages();
         reset(mPostureController);
+        cleanUp(mDialog);
     }
 
     private void cleanUp(VolumeDialogImpl dialog) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 7ebf6c8..1b623a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -341,6 +341,7 @@
                 mConfigurationController,
                 mKeyguardViewMediator,
                 mKeyguardBypassController,
+                syncExecutor,
                 mColorExtractor,
                 mDumpManager,
                 mKeyguardStateController,
@@ -419,6 +420,7 @@
                 syncExecutor,
                 mock(Handler.class),
                 mTaskViewTransitions,
+                mTransitions,
                 mock(SyncTransactionQueue.class),
                 mock(IWindowManager.class),
                 mBubbleProperties);
@@ -510,6 +512,11 @@
     }
 
     @Test
+    public void instantiateController_registerTransitionObserver() {
+        verify(mTransitions).registerObserver(any());
+    }
+
+    @Test
     public void testAddBubble() {
         mBubbleController.updateBubble(mBubbleEntry);
         assertTrue(mBubbleController.hasBubbles());
@@ -1469,6 +1476,34 @@
     }
 
     @Test
+    public void testBroadcastReceiverCloseDialogs_reasonHomeKey() {
+        spyOn(mContext);
+        mBubbleController.updateBubble(mBubbleEntry);
+        mBubbleData.setExpanded(true);
+
+        verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+                mFilterArgumentCaptor.capture(), eq(Context.RECEIVER_EXPORTED));
+        Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        i.putExtra("reason", "homekey");
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+        assertStackCollapsed();
+    }
+
+    @Test
+    public void testBroadcastReceiverCloseDialogs_reasonRecentsKey() {
+        spyOn(mContext);
+        mBubbleController.updateBubble(mBubbleEntry);
+        mBubbleData.setExpanded(true);
+
+        verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
+                mFilterArgumentCaptor.capture(), eq(Context.RECEIVER_EXPORTED));
+        Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        i.putExtra("reason", "recentapps");
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
+        assertStackCollapsed();
+    }
+
+    @Test
     public void testBroadcastReceiver_screenOff() {
         spyOn(mContext);
         mBubbleController.updateBubble(mBubbleEntry);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 5855347..9ad234e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -43,6 +43,7 @@
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.taskview.TaskViewTransitions;
+import com.android.wm.shell.transition.Transitions;
 
 import java.util.Optional;
 
@@ -74,6 +75,7 @@
             ShellExecutor shellMainExecutor,
             Handler shellMainHandler,
             TaskViewTransitions taskViewTransitions,
+            Transitions transitions,
             SyncTransactionQueue syncQueue,
             IWindowManager wmService,
             BubbleProperties bubbleProperties) {
@@ -82,7 +84,8 @@
                 windowManagerShellWrapper, userManager, launcherApps, bubbleLogger,
                 taskStackListener, shellTaskOrganizer, positioner, displayController,
                 oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
-                new SyncExecutor(), taskViewTransitions, syncQueue, wmService, bubbleProperties);
+                new SyncExecutor(), taskViewTransitions, transitions,
+                syncQueue, wmService, bubbleProperties);
         setInflateSynchronously(true);
         onInit();
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 28b7d41..aa88a46 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -166,7 +166,9 @@
         }
         disallowTestableLooperAsMainThread();
         mContext.cleanUpReceivers(this.getClass().getSimpleName());
-        mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
+        if (mFakeBroadcastDispatcher != null) {
+            mFakeBroadcastDispatcher.cleanUpReceivers(this.getClass().getSimpleName());
+        }
     }
 
     @AfterClass
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 715d661..2ac625d 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
@@ -30,13 +30,24 @@
     }
 }
 
+/** Creates a mock [DisplayRepository.PendingDisplay]. */
+fun createPendingDisplay(id: Int = 0): DisplayRepository.PendingDisplay =
+    mock<DisplayRepository.PendingDisplay> { whenever(this.id).thenReturn(id) }
+
 /** Fake [DisplayRepository] implementation for testing. */
 class FakeDisplayRepository : DisplayRepository {
     private val flow = MutableSharedFlow<Set<Display>>()
+    private val pendingDisplayFlow = MutableSharedFlow<DisplayRepository.PendingDisplay?>()
 
     /** Emits [value] as [displays] flow value. */
     suspend fun emit(value: Set<Display>) = flow.emit(value)
 
+    /** Emits [value] as [pendingDisplay] flow value. */
+    suspend fun emit(value: DisplayRepository.PendingDisplay?) = pendingDisplayFlow.emit(value)
+
     override val displays: Flow<Set<Display>>
         get() = flow
+
+    override val pendingDisplay: Flow<DisplayRepository.PendingDisplay?>
+        get() = pendingDisplayFlow
 }
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 faebcaa..cc0c943 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
@@ -81,7 +81,7 @@
     override val linearDozeAmount: Flow<Float> = _dozeAmount
 
     private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
-    override val statusBarState: Flow<StatusBarState> = _statusBarState
+    override val statusBarState: StateFlow<StatusBarState> = _statusBarState
 
     private val _dozeTransitionModel = MutableStateFlow(DozeTransitionModel())
     override val dozeTransitionModel: Flow<DozeTransitionModel> = _dozeTransitionModel
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index 8c1ef1d..2e3bb2b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -23,7 +23,11 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.util.mockito.mock
 
 /**
  * Simply put, I got tired of adding a constructor argument and then having to tweak dozens of
@@ -35,16 +39,19 @@
     @JvmStatic
     fun create(
         featureFlags: FakeFeatureFlags = createFakeFeatureFlags(),
+        sceneContainerFlags: SceneContainerFlags = FakeSceneContainerFlags(),
         repository: FakeKeyguardRepository = FakeKeyguardRepository(),
         commandQueue: FakeCommandQueue = FakeCommandQueue(),
         bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
         configurationRepository: FakeConfigurationRepository = FakeConfigurationRepository(),
         shadeRepository: FakeShadeRepository = FakeShadeRepository(),
+        sceneInteractor: SceneInteractor = mock(),
     ): WithDependencies {
         return WithDependencies(
             repository = repository,
             commandQueue = commandQueue,
             featureFlags = featureFlags,
+            sceneContainerFlags = sceneContainerFlags,
             bouncerRepository = bouncerRepository,
             configurationRepository = configurationRepository,
             shadeRepository = shadeRepository,
@@ -52,9 +59,11 @@
                 repository = repository,
                 commandQueue = commandQueue,
                 featureFlags = featureFlags,
+                sceneContainerFlags = sceneContainerFlags,
                 bouncerRepository = bouncerRepository,
                 configurationRepository = configurationRepository,
                 shadeRepository = shadeRepository,
+                sceneInteractorProvider = { sceneInteractor },
             )
         )
     }
@@ -68,6 +77,7 @@
         val repository: FakeKeyguardRepository,
         val commandQueue: FakeCommandQueue,
         val featureFlags: FakeFeatureFlags,
+        val sceneContainerFlags: SceneContainerFlags,
         val bouncerRepository: FakeKeyguardBouncerRepository,
         val configurationRepository: FakeConfigurationRepository,
         val shadeRepository: FakeShadeRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
index 05c63b6..5cf656c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorFactory.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.util.mockito.mock
 import dagger.Lazy
@@ -31,8 +33,9 @@
     fun create(
         scope: CoroutineScope,
         repository: FakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository(),
+        featureFlags: FakeFeatureFlags = FakeFeatureFlagsClassic(),
         keyguardInteractor: KeyguardInteractor =
-            KeyguardInteractorFactory.create().keyguardInteractor,
+            KeyguardInteractorFactory.create(featureFlags = featureFlags).keyguardInteractor,
         fromLockscreenTransitionInteractor: Lazy<FromLockscreenTransitionInteractor> = Lazy {
             mock<FromLockscreenTransitionInteractor>()
         },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
index 3334f3e..b92d946 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
@@ -32,6 +32,8 @@
     var lastWakeWhy: String? = null
     var lastWakeReason: Int? = null
 
+    var userTouchRegistered = false
+
     fun setInteractive(value: Boolean) {
         _isInteractive.value = value
     }
@@ -40,4 +42,8 @@
         lastWakeWhy = why
         lastWakeReason = wakeReason
     }
+
+    override fun userTouch() {
+        userTouchRegistered = true
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 6b40f8e..9dea0a0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -27,8 +27,11 @@
 import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.classifier.domain.interactor.FalsingInteractor
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeCommandQueue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -37,8 +40,10 @@
 import com.android.systemui.keyguard.shared.model.WakeSleepReason
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
 import com.android.systemui.keyguard.shared.model.WakefulnessState
+import com.android.systemui.power.data.repository.FakePowerRepository
 import com.android.systemui.scene.data.repository.SceneContainerRepository
 import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneContainerConfig
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.shade.data.repository.FakeShadeRepository
@@ -63,11 +68,8 @@
 ) {
     val testDispatcher = StandardTestDispatcher()
     val testScope = TestScope(testDispatcher)
-    val featureFlags =
-        FakeFeatureFlags().apply {
-            set(Flags.SCENE_CONTAINER, true)
-            set(Flags.FACE_AUTH_REFACTOR, false)
-        }
+    val featureFlags = FakeFeatureFlagsClassic().apply { set(Flags.FACE_AUTH_REFACTOR, false) }
+    val sceneContainerFlags = FakeSceneContainerFlags().apply { enabled = true }
     private val userRepository: UserRepository by lazy {
         FakeUserRepository().apply {
             val users = listOf(UserInfo(/* id=  */ 0, "name", /* flags= */ 0))
@@ -93,8 +95,13 @@
         }
     }
 
+    val powerRepository: FakePowerRepository by lazy { FakePowerRepository() }
+
     private val context = test.context
 
+    private val falsingCollectorFake: FalsingCollector by lazy { FalsingCollectorFake() }
+    private var falsingInteractor: FalsingInteractor? = null
+
     fun fakeSceneContainerRepository(
         containerConfig: SceneContainerConfig = fakeSceneContainerConfig(),
     ): SceneContainerRepository {
@@ -126,6 +133,7 @@
         return SceneInteractor(
             applicationScope = applicationScope(),
             repository = repository,
+            powerRepository = powerRepository,
             logger = mock(),
         )
     }
@@ -149,18 +157,16 @@
         )
     }
 
-    fun keyguardRepository(): FakeKeyguardRepository {
-        return keyguardRepository
-    }
-
     fun keyguardInteractor(repository: KeyguardRepository): KeyguardInteractor {
         return KeyguardInteractor(
             repository = repository,
             commandQueue = FakeCommandQueue(),
             featureFlags = featureFlags,
+            sceneContainerFlags = sceneContainerFlags,
             bouncerRepository = FakeKeyguardBouncerRepository(),
             configurationRepository = FakeConfigurationRepository(),
             shadeRepository = FakeShadeRepository(),
+            sceneInteractorProvider = { sceneInteractor() },
         )
     }
 
@@ -174,7 +180,8 @@
             repository = BouncerRepository(),
             authenticationInteractor = authenticationInteractor,
             sceneInteractor = sceneInteractor,
-            featureFlags = featureFlags,
+            flags = sceneContainerFlags,
+            falsingInteractor = falsingInteractor(),
         )
     }
 
@@ -187,10 +194,18 @@
             applicationScope = applicationScope(),
             bouncerInteractor = bouncerInteractor,
             authenticationInteractor = authenticationInteractor,
-            featureFlags = featureFlags,
+            flags = sceneContainerFlags,
         )
     }
 
+    fun falsingInteractor(collector: FalsingCollector = falsingCollector()): FalsingInteractor {
+        return falsingInteractor ?: FalsingInteractor(collector).also { falsingInteractor = it }
+    }
+
+    fun falsingCollector(): FalsingCollector {
+        return falsingCollectorFake
+    }
+
     private fun applicationScope(): CoroutineScope {
         return testScope.backgroundScope
     }
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
similarity index 62%
copy from tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
index fe91260..01a1ece 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.apkverity.feature_x;
+package com.android.systemui.scene.shared.flag
 
-import android.app.Activity;
+class FakeSceneContainerFlags(
+    var enabled: Boolean = false,
+) : SceneContainerFlags {
 
-/** Placeholder class just to generate some dex */
-public class DummyActivity extends Activity {}
+    override fun isEnabled(): Boolean {
+        return enabled
+    }
+
+    override fun requirementDescription(): String {
+        return ""
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index ccddca2..08152a3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -33,8 +33,12 @@
     private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
     override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
 
-    private val _shadeExpansion = MutableStateFlow(0f)
-    override val shadeExpansion = _shadeExpansion
+    private val _lockscreenShadeExpansion = MutableStateFlow(0f)
+    override val lockscreenShadeExpansion = _lockscreenShadeExpansion
+
+    private val _legacyShadeExpansion = MutableStateFlow(0f)
+    @Deprecated("Use ShadeInteractor instead")
+    override val legacyShadeExpansion = _legacyShadeExpansion
 
     fun setShadeModel(model: ShadeModel) {
         _shadeModel.value = model
@@ -48,7 +52,12 @@
         _udfpsTransitionToFullShadeProgress.value = progress
     }
 
-    override fun setShadeExpansion(expansion: Float) {
-        _shadeExpansion.value = expansion
+    override fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) {
+        _lockscreenShadeExpansion.value = lockscreenShadeExpansion
+    }
+
+    @Deprecated("Should only be called by NPVC and tests")
+    override fun setLegacyShadeExpansion(expandedFraction: Float) {
+        _legacyShadeExpansion.value = expandedFraction
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 03e3423..3774d1d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -84,10 +84,6 @@
     }
 
     @Override
-    public void removeAllIconsForSlot(String slot) {
-    }
-
-    @Override
     public void setIconAccessibilityLiveRegion(String slot, int mode) {
     }
 
diff --git a/packages/WallpaperBackup/Android.bp b/packages/WallpaperBackup/Android.bp
index 8acc508..155dc1a 100644
--- a/packages/WallpaperBackup/Android.bp
+++ b/packages/WallpaperBackup/Android.bp
@@ -27,9 +27,6 @@
     name: "WallpaperBackup",
     defaults: ["platform_app_defaults"],
     srcs: ["src/**/*.java"],
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
     platform_apis: true,
     certificate: "platform",
     privileged: false,
diff --git a/packages/WallpaperBackup/proguard.flags b/packages/WallpaperBackup/proguard.flags
deleted file mode 100644
index 247e6ef..0000000
--- a/packages/WallpaperBackup/proguard.flags
+++ /dev/null
@@ -1 +0,0 @@
--keep class com.android.wallpaperbackup.WallpaperBackupAgent
diff --git a/packages/services/VirtualCamera/OWNERS b/packages/services/VirtualCamera/OWNERS
new file mode 100644
index 0000000..c66443f
--- /dev/null
+++ b/packages/services/VirtualCamera/OWNERS
@@ -0,0 +1,3 @@
+include /services/companion/java/com/android/server/companion/virtual/OWNERS
+caen@google.com
+jsebechlebsky@google.com
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index f3a540b..cd83f8f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -389,11 +389,19 @@
     @Override
     public void onMotionEvent(MotionEvent transformedEvent, MotionEvent rawEvent,
             int policyFlags) {
+        if (!mInstalled) {
+            Slog.w(TAG, "onMotionEvent called before input filter installed!");
+            return;
+        }
         sendInputEvent(transformedEvent, policyFlags);
     }
 
     @Override
     public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (!mInstalled) {
+            Slog.w(TAG, "onKeyEvent called before input filter installed!");
+            return;
+        }
         sendInputEvent(event, policyFlags);
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index cbf4cce..93ba362 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -63,6 +63,7 @@
 import android.app.RemoteAction;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetManagerInternal;
+import android.companion.virtual.VirtualDeviceManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -928,18 +929,32 @@
         mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, mMainHandler,
                 Context.RECEIVER_EXPORTED);
 
-        final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final int deviceId = intent.getIntExtra(
-                        EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
-                mProxyManager.clearConnections(deviceId);
+        if (android.companion.virtual.flags.Flags.vdmPublicApis()) {
+            VirtualDeviceManager vdm = mContext.getSystemService(VirtualDeviceManager.class);
+            if (vdm != null) {
+                vdm.registerVirtualDeviceListener(mContext.getMainExecutor(),
+                        new VirtualDeviceManager.VirtualDeviceListener() {
+                            @Override
+                            public void onVirtualDeviceClosed(int deviceId) {
+                                mProxyManager.clearConnections(deviceId);
+                            }
+                        });
             }
-        };
+        } else {
+            final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    final int deviceId = intent.getIntExtra(
+                            EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT);
+                    mProxyManager.clearConnections(deviceId);
+                }
+            };
 
-        final IntentFilter virtualDeviceFilter = new IntentFilter(ACTION_VIRTUAL_DEVICE_REMOVED);
-        mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter,
-                Context.RECEIVER_NOT_EXPORTED);
+            final IntentFilter virtualDeviceFilter = new IntentFilter(
+                    ACTION_VIRTUAL_DEVICE_REMOVED);
+            mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter,
+                    Context.RECEIVER_NOT_EXPORTED);
+        }
     }
 
     /**
diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp
index eb23f2f..d43a219 100644
--- a/services/autofill/Android.bp
+++ b/services/autofill/Android.bp
@@ -19,4 +19,19 @@
     defaults: ["platform_service_defaults"],
     srcs: [":services.autofill-sources"],
     libs: ["services.core"],
+    static_libs: ["autofill_flags_java_lib"],
+}
+
+aconfig_declarations {
+    name: "autofill_flags",
+    package: "android.service.autofill",
+    srcs: [
+        "bugfixes.aconfig",
+        "features.aconfig",
+    ],
+}
+
+java_aconfig_library {
+    name: "autofill_flags_java_lib",
+    aconfig_declarations: "autofill_flags",
 }
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
new file mode 100644
index 0000000..ef23754
--- /dev/null
+++ b/services/autofill/bugfixes.aconfig
@@ -0,0 +1,8 @@
+package: "android.service.autofill"
+
+flag {
+  name: "test"
+  namespace: "autofill"
+  description: "Test flag "
+  bug: "297380045"
+}
\ No newline at end of file
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
new file mode 100644
index 0000000..1e44de6
--- /dev/null
+++ b/services/autofill/features.aconfig
@@ -0,0 +1 @@
+package: "android.service.autofill"
\ No newline at end of file
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index ec4203e..cad8fcf 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -594,8 +594,6 @@
 
     // Called by Shell command.
     int getMaxPartitions() {
-        enforceCallingPermissionForManagement();
-
         synchronized (mLock) {
             return sPartitionMaxCount;
         }
@@ -628,8 +626,6 @@
 
     // Called by Shell command.
     int getMaxVisibleDatasets() {
-        enforceCallingPermissionForManagement();
-
         synchronized (sLock) {
             return sVisibleDatasetsMaxCount;
         }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index c66fb81..39756df 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -26,11 +26,14 @@
 import android.os.ShellCommand;
 import android.os.UserHandle;
 import android.service.autofill.AutofillFieldClassificationService.Scores;
+import android.service.autofill.Flags;
 import android.view.autofill.AutofillManager;
 
 import com.android.internal.os.IResultReceiver;
 
 import java.io.PrintWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -60,6 +63,8 @@
                 return requestGet(pw);
             case "set":
                 return requestSet(pw);
+            case "flags":
+                return requestFlags(pw);
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -67,7 +72,7 @@
 
     @Override
     public void onHelp() {
-        try (final PrintWriter pw = getOutPrintWriter();) {
+        try (final PrintWriter pw = getOutPrintWriter(); ) {
             pw.println("AutoFill Service (autofill) commands:");
             pw.println("  help");
             pw.println("    Prints this help text.");
@@ -109,21 +114,24 @@
             pw.println("    Sets whether binding to services provided by instant apps is allowed");
             pw.println("");
             pw.println("  set temporary-augmented-service USER_ID [COMPONENT_NAME DURATION]");
-            pw.println("    Temporarily (for DURATION ms) changes the augmented autofill service "
-                    + "implementation.");
+            pw.println(
+                    "    Temporarily (for DURATION ms) changes the augmented autofill service "
+                            + "implementation.");
             pw.println("    To reset, call with just the USER_ID argument.");
             pw.println("");
             pw.println("  set default-augmented-service-enabled USER_ID [true|false]");
             pw.println("    Enable / disable the default augmented autofill service for the user.");
             pw.println("");
             pw.println("  set temporary-detection-service USER_ID [COMPONENT_NAME DURATION]");
-            pw.println("    Temporarily (for DURATION ms) changes the autofill detection service "
-                    + "implementation.");
+            pw.println(
+                    "    Temporarily (for DURATION ms) changes the autofill detection service "
+                            + "implementation.");
             pw.println("    To reset, call with [COMPONENT_NAME 0].");
             pw.println("");
             pw.println("  get default-augmented-service-enabled USER_ID");
-            pw.println("    Checks whether the default augmented autofill service is enabled for "
-                    + "the user.");
+            pw.println(
+                    "    Checks whether the default augmented autofill service is enabled for "
+                            + "the user.");
             pw.println("");
             pw.println("  list sessions [--user USER_ID]");
             pw.println("    Lists all pending sessions.");
@@ -134,9 +142,36 @@
             pw.println("  reset");
             pw.println("    Resets all pending sessions and cached service connections.");
             pw.println("");
+            pw.println("  flags");
+            pw.println("    Prints out all autofill related flags.");
+            pw.println("");
         }
     }
 
+    private int requestFlags(PrintWriter pw) {
+
+        if (Flags.test()) {
+            pw.println("Hello Flag World!");
+            pw.println("");
+        }
+
+        try {
+            Method[] flagMethods = Flags.class.getMethods();
+            // For some reason, unreferenced flags do not show up here
+            // Maybe compiler optomized them out of bytecode?
+            for (Method method : flagMethods) {
+                if (Modifier.isPublic(method.getModifiers())) {
+                    pw.println(method.getName() + ": " + method.invoke(null));
+                }
+            }
+        } catch (Exception ex) {
+            pw.println(ex);
+            return -1;
+        }
+
+        return 0;
+    }
+
     private int requestGet(PrintWriter pw) {
         final String what = getNextArgRequired();
         switch(what) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 4688658..423b85f 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -56,7 +56,7 @@
     private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
     private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
 
-    private final FillServiceCallbacks mCallbacks;
+    private FillServiceCallbacks mCallbacks;
     private final Object mLock = new Object();
     private CompletableFuture<FillResponse> mPendingFillRequest;
     private int mPendingFillRequestId = INVALID_REQUEST_ID;
@@ -128,9 +128,12 @@
      */
     public int cancelCurrentRequest() {
         synchronized (mLock) {
-            return mPendingFillRequest != null && mPendingFillRequest.cancel(false)
+            int canceledRequestId = mPendingFillRequest != null && mPendingFillRequest.cancel(false)
                     ? mPendingFillRequestId
                     : INVALID_REQUEST_ID;
+            mPendingFillRequest = null;
+            mPendingFillRequestId = INVALID_REQUEST_ID;
+            return canceledRequestId;
         }
     }
 
@@ -184,6 +187,10 @@
                 mPendingFillRequest = null;
                 mPendingFillRequestId = INVALID_REQUEST_ID;
             }
+            if (mCallbacks == null) {
+                Slog.w(TAG, "Error calling RemoteFillService - service already unbound");
+                return;
+            }
             if (err == null) {
                 mCallbacks.onFillRequestSuccess(request.getId(), res,
                         mComponentName.getPackageName(), request.getFlags());
@@ -220,6 +227,10 @@
             return save;
         }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS)
                 .whenComplete((res, err) -> Handler.getMain().post(() -> {
+                    if (mCallbacks == null) {
+                        Slog.w(TAG, "Error calling RemoteFillService - service already unbound");
+                        return;
+                    }
                     if (err == null) {
                         mCallbacks.onSaveRequestSuccess(mComponentName.getPackageName(), res);
                     } else {
@@ -234,6 +245,8 @@
     }
 
     public void destroy() {
+        cancelCurrentRequest();
         unbind();
+        mCallbacks = null;
     }
 }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index b573800..3b02be5 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -1750,12 +1750,8 @@
 
         synchronized (mClearDataLock) {
             mClearingData = true;
-            try {
-                mActivityManager.clearApplicationUserData(packageName, keepSystemState, observer,
-                        mUserId);
-            } catch (RemoteException e) {
-                // can't happen because the activity manager is in this process
-            }
+            mActivityManagerInternal.clearApplicationUserData(packageName, keepSystemState,
+                    /*isRestore=*/ true, observer, mUserId);
 
             // Only wait 30 seconds for the clear data to happen.
             long timeoutMark = System.currentTimeMillis() + CLEAR_DATA_TIMEOUT_INTERVAL;
diff --git a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
index 6675568..ce4067c 100644
--- a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
+++ b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
@@ -19,6 +19,7 @@
 import static android.hardware.camera2.CameraInjectionSession.InjectionStatusCallback.ERROR_INJECTION_UNSUPPORTED;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -146,6 +147,7 @@
      *
      * @param runningUids uids of the application running on the virtual display
      */
+    @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
     public void blockCameraAccessIfNeeded(Set<Integer> runningUids) {
         synchronized (mLock) {
             for (int i = 0; i < mAppsToBlockOnVirtualDevice.size(); i++) {
@@ -181,6 +183,7 @@
     }
 
     @Override
+    @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
     public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) {
         synchronized (mLock) {
             InjectionSessionData data = mPackageToSessionData.get(packageName);
@@ -243,6 +246,7 @@
     /**
      * Turns on blocking for a particular camera and package.
      */
+    @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
     private void startBlocking(String packageName, String cameraId) {
         try {
             Slog.d(
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 34033e2..b07a0bb 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -17,6 +17,7 @@
 package com.android.server.companion.virtual;
 
 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
@@ -26,8 +27,6 @@
 import android.app.WindowConfiguration;
 import android.app.compat.CompatChanges;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
-import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.ComponentName;
@@ -46,7 +45,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.BlockedAppStreamingActivity;
 
-import java.util.List;
 import java.util.Set;
 
 
@@ -108,18 +106,14 @@
     public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
     @NonNull
     private final ArraySet<UserHandle> mAllowedUsers;
-    @Nullable
-    private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
-    @Nullable
-    private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
-    @Nullable
-    private final ArraySet<ComponentName> mAllowedActivities;
-    @Nullable
-    private final ArraySet<ComponentName> mBlockedActivities;
+    private final boolean mActivityLaunchAllowedByDefault;
+    @NonNull
+    private final ArraySet<ComponentName> mActivityPolicyExceptions;
+    private final boolean mCrossTaskNavigationAllowedByDefault;
+    @NonNull
+    private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
     private final Object mGenericWindowPolicyControllerLock = new Object();
-    @ActivityPolicy
-    private final int mDefaultActivityPolicy;
-    private final ActivityBlockedCallback mActivityBlockedCallback;
+    @Nullable private final ActivityBlockedCallback mActivityBlockedCallback;
     private int mDisplayId = Display.INVALID_DISPLAY;
 
     @NonNull
@@ -134,9 +128,10 @@
     private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners =
             new ArraySet<>();
     @Nullable private final SecureWindowCallback mSecureWindowCallback;
-    @Nullable private final Set<String> mDisplayCategories;
+    @NonNull private final Set<String> mDisplayCategories;
 
-    private final boolean mShowTasksInHostDeviceRecents;
+    @GuardedBy("mGenericWindowPolicyControllerLock")
+    private boolean mShowTasksInHostDeviceRecents;
 
     /**
      * Creates a window policy controller that is generic to the different use cases of virtual
@@ -145,18 +140,14 @@
      * @param windowFlags The window flags that this controller is interested in.
      * @param systemWindowFlags The system window flags that this controller is interested in.
      * @param allowedUsers The set of users that are allowed to stream in this display.
-     * @param allowedCrossTaskNavigations The set of components explicitly allowed to navigate
-     *   across tasks on this device.
-     * @param blockedCrossTaskNavigations The set of components explicitly blocked from
-     *   navigating across tasks on this device.
-     * @param allowedActivities The set of activities explicitly allowed to stream on this device.
-     *   Used only if the {@code activityPolicy} is
-     *   {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}.
-     * @param blockedActivities The set of activities explicitly blocked from streaming on this
-     *   device. Used only if the {@code activityPolicy} is
-     *   {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED}
-     * @param defaultActivityPolicy Whether activities are default allowed to be displayed or
-     *   blocked.
+     * @param activityLaunchAllowedByDefault Whether activities are default allowed to be launched
+     *   or blocked.
+     * @param activityPolicyExceptions The set of activities explicitly exempt from the default
+     *   activity policy.
+     * @param crossTaskNavigationAllowedByDefault Whether cross task navigations are allowed by
+     *   default or not.
+     * @param crossTaskNavigationExceptions The set of components explicitly exempt from the default
+     *   navigation policy.
      * @param activityListener Activity listener to listen for activity changes.
      * @param activityBlockedCallback Callback that is called when an activity is blocked from
      *   launching.
@@ -168,25 +159,23 @@
      */
     public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
             @NonNull ArraySet<UserHandle> allowedUsers,
-            @NonNull Set<ComponentName> allowedCrossTaskNavigations,
-            @NonNull Set<ComponentName> blockedCrossTaskNavigations,
-            @NonNull Set<ComponentName> allowedActivities,
-            @NonNull Set<ComponentName> blockedActivities,
-            @ActivityPolicy int defaultActivityPolicy,
-            @NonNull ActivityListener activityListener,
-            @NonNull PipBlockedCallback pipBlockedCallback,
-            @NonNull ActivityBlockedCallback activityBlockedCallback,
-            @NonNull SecureWindowCallback secureWindowCallback,
-            @NonNull IntentListenerCallback intentListenerCallback,
+            boolean activityLaunchAllowedByDefault,
+            @NonNull Set<ComponentName> activityPolicyExceptions,
+            boolean crossTaskNavigationAllowedByDefault,
+            @NonNull Set<ComponentName> crossTaskNavigationExceptions,
+            @Nullable ActivityListener activityListener,
+            @Nullable PipBlockedCallback pipBlockedCallback,
+            @Nullable ActivityBlockedCallback activityBlockedCallback,
+            @Nullable SecureWindowCallback secureWindowCallback,
+            @Nullable IntentListenerCallback intentListenerCallback,
             @NonNull Set<String> displayCategories,
             boolean showTasksInHostDeviceRecents) {
         super();
         mAllowedUsers = allowedUsers;
-        mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
-        mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
-        mAllowedActivities = new ArraySet<>(allowedActivities);
-        mBlockedActivities = new ArraySet<>(blockedActivities);
-        mDefaultActivityPolicy = defaultActivityPolicy;
+        mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
+        mActivityPolicyExceptions = new ArraySet<>(activityPolicyExceptions);
+        mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault;
+        mCrossTaskNavigationExceptions = new ArraySet<>(crossTaskNavigationExceptions);
         mActivityBlockedCallback = activityBlockedCallback;
         setInterestedWindowFlags(windowFlags, systemWindowFlags);
         mActivityListener = activityListener;
@@ -204,6 +193,15 @@
         mDisplayId = displayId;
     }
 
+    /**
+     * Set whether to show activities in recents on the host device.
+     */
+    public void setShowInHostDeviceRecents(boolean showInHostDeviceRecents) {
+        synchronized (mGenericWindowPolicyControllerLock) {
+            mShowTasksInHostDeviceRecents = showInHostDeviceRecents;
+        }
+    }
+
     /** Register a listener for running applications changes. */
     public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
         synchronized (mGenericWindowPolicyControllerLock) {
@@ -219,28 +217,39 @@
     }
 
     @Override
-    public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
-            @WindowConfiguration.WindowingMode int windowingMode) {
-        if (!isWindowingModeSupported(windowingMode)) {
+    public boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
+            @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
+            int launchingFromDisplayId, boolean isNewTask) {
+        if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, isNewTask)) {
+            if (mActivityBlockedCallback != null) {
+                mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+            }
             return false;
         }
-        // Can't display all the activities if any of them don't want to be displayed.
-        final int activityCount = activities.size();
-        for (int i = 0; i < activityCount; i++) {
-            final ActivityInfo aInfo = activities.get(i);
-            if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
-                mActivityBlockedCallback.onActivityBlocked(mDisplayId, aInfo);
-                return false;
-            }
+        if (mIntentListenerCallback != null && intent != null
+                && mIntentListenerCallback.shouldInterceptIntent(intent)) {
+            Slog.d(TAG, "Virtual device intercepting intent");
+            return false;
         }
         return true;
     }
 
     @Override
-    public boolean canActivityBeLaunched(ActivityInfo activityInfo,
-            Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
-            int launchingFromDisplayId, boolean isNewTask) {
+    public boolean canContainActivity(@NonNull ActivityInfo activityInfo,
+            @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+            boolean isNewTask) {
         if (!isWindowingModeSupported(windowingMode)) {
+            Slog.d(TAG, "Virtual device doesn't support windowing mode " + windowingMode);
+            return false;
+        }
+        if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
+            Slog.d(TAG, "Virtual device requires android:canDisplayOnRemoteDevices=true");
+            return false;
+        }
+        final UserHandle activityUser =
+                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
+        if (!mAllowedUsers.contains(activityUser)) {
+            Slog.d(TAG, "Virtual device launch disallowed from user " + activityUser);
             return false;
         }
 
@@ -249,54 +258,54 @@
             // The error dialog alerting users that streaming is blocked is always allowed.
             return true;
         }
-
-        if (!canContainActivity(activityInfo, /* windowFlags= */  0, /* systemWindowFlags= */ 0)) {
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+        if (!activityMatchesDisplayCategory(activityInfo)) {
+            Slog.d(TAG, "The activity's required display category '"
+                    + activityInfo.requiredDisplayCategory
+                    + "' not found on virtual display with the following categories: "
+                    + mDisplayCategories);
             return false;
         }
-
-        if (launchingFromDisplayId == Display.DEFAULT_DISPLAY) {
-            return true;
-        }
-        if (isNewTask && !mBlockedCrossTaskNavigations.isEmpty()
-                && mBlockedCrossTaskNavigations.contains(activityComponent)) {
-            Slog.d(TAG, "Virtual device blocking cross task navigation of " + activityComponent);
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+        if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExceptions,
+                activityComponent)) {
+            Slog.d(TAG, "Virtual device launch disallowed by policy: " + activityComponent);
             return false;
         }
-        if (isNewTask && !mAllowedCrossTaskNavigations.isEmpty()
-                && !mAllowedCrossTaskNavigations.contains(activityComponent)) {
-            Slog.d(TAG, "Virtual device not allowing cross task navigation of "
+        if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY
+                && !isAllowedByPolicy(mCrossTaskNavigationAllowedByDefault,
+                        mCrossTaskNavigationExceptions, activityComponent)) {
+            Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
                     + activityComponent);
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
-            return false;
-        }
-
-        if (mIntentListenerCallback != null && intent != null
-                && mIntentListenerCallback.shouldInterceptIntent(intent)) {
-            Slog.d(TAG, "Virtual device has intercepted intent");
             return false;
         }
 
         return true;
     }
 
-
     @Override
+    @SuppressWarnings("AndroidFrameworkRequiresPermission")
     public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
             int systemWindowFlags) {
         // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
         // aware that the virtual display has a secure window on top.
-        if ((windowFlags & FLAG_SECURE) != 0) {
+        if ((windowFlags & FLAG_SECURE) != 0 && mSecureWindowCallback != null) {
             // Post callback on the main thread, so it doesn't block activity launching.
             mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(mDisplayId,
                     activityInfo.applicationInfo.uid));
         }
 
-        if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
-            return false;
+        if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
+                activityInfo.packageName,
+                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid))) {
+            // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
+            if ((windowFlags & FLAG_SECURE) != 0
+                    || (systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+                if (mActivityBlockedCallback != null) {
+                    mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+                }
+                return false;
+            }
         }
+
         return true;
     }
 
@@ -335,7 +344,9 @@
 
     @Override
     public boolean canShowTasksInHostDeviceRecents() {
-        return mShowTasksInHostDeviceRecents;
+        synchronized (mGenericWindowPolicyControllerLock) {
+            return mShowTasksInHostDeviceRecents;
+        }
     }
 
     @Override
@@ -343,9 +354,9 @@
         if (super.isEnteringPipAllowed(uid)) {
             return true;
         }
-        mHandler.post(() -> {
-            mPipBlockedCallback.onEnteringPipBlocked(uid);
-        });
+        if (mPipBlockedCallback != null) {
+            mHandler.post(() -> mPipBlockedCallback.onEnteringPipBlocked(uid));
+        }
         return false;
     }
 
@@ -365,54 +376,13 @@
         }
         return activityInfo.requiredDisplayCategory != null
                     && mDisplayCategories.contains(activityInfo.requiredDisplayCategory);
-
     }
 
-    private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags,
-            int systemWindowFlags) {
-        if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
-            return false;
-        }
-        ComponentName activityComponent = activityInfo.getComponentName();
-        if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
-            // The error dialog alerting users that streaming is blocked is always allowed. Need to
-            // run before the clauses below to ensure error dialog always shows up.
-            return true;
-        }
-        if (!activityMatchesDisplayCategory(activityInfo)) {
-            Slog.d(TAG, String.format(
-                    "The activity's required display category: %s is not found on virtual display"
-                            + " with the following categories: %s",
-                    activityInfo.requiredDisplayCategory, mDisplayCategories.toString()));
-            return false;
-        }
-        final UserHandle activityUser =
-                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
-        if (!mAllowedUsers.contains(activityUser)) {
-            Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser);
-            return false;
-        }
-        if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED
-                && mBlockedActivities.contains(activityComponent)) {
-            Slog.d(TAG, "Virtual device blocking launch of " + activityComponent);
-            return false;
-        }
-        if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED
-                && !mAllowedActivities.contains(activityComponent)) {
-            Slog.d(TAG, activityComponent + " is not in the allowed list.");
-            return false;
-        }
-        if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
-                activityInfo.packageName, activityUser)) {
-            // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
-            if ((windowFlags & FLAG_SECURE) != 0) {
-                return false;
-            }
-            if ((systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
-                return false;
-            }
-        }
-        return true;
+    private boolean isAllowedByPolicy(boolean allowedByDefault, ArraySet<ComponentName> exceptions,
+            ComponentName component) {
+        // Either allowed and the exceptions do not contain the component,
+        // or disallowed and the exceptions contain the component.
+        return allowedByDefault != exceptions.contains(component);
     }
 
     @VisibleForTesting
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index 307f7bf..eeaa423 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.companion.virtual;
 
+import static android.text.TextUtils.formatSimple;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.StringDef;
@@ -350,7 +352,7 @@
     }
 
     private static String createPhys(@PhysType String type) {
-        return String.format("virtual%s:%d", type, sNextPhysId.getAndIncrement());
+        return formatSimple("virtual%s:%d", type, sNextPhysId.getAndIncrement());
     }
 
     private void setUniqueIdAssociation(int displayId, String phys) {
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
index a831401..e9241dd 100644
--- a/services/companion/java/com/android/server/companion/virtual/SensorController.java
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -323,8 +323,5 @@
         SensorCreationException(String message) {
             super(message);
         }
-        SensorCreationException(String message, Exception cause) {
-            super(message, cause);
-        }
     }
 }
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 f23fe2a..8f765e4 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -19,12 +19,17 @@
 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_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
 import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.StringRes;
 import android.annotation.UserIdInt;
 import android.app.Activity;
@@ -36,11 +41,13 @@
 import android.companion.virtual.IVirtualDeviceActivityListener;
 import android.companion.virtual.IVirtualDeviceIntentInterceptor;
 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
+import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceManager.ActivityListener;
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.companion.virtual.sensor.VirtualSensorEvent;
 import android.content.AttributionSource;
@@ -78,12 +85,15 @@
 import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.WindowManager;
 import android.widget.Toast;
 
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.BlockedAppStreamingActivity;
@@ -93,7 +103,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -128,8 +137,8 @@
     private final int mOwnerUid;
     private final VirtualDeviceLog mVirtualDeviceLog;
     private final String mOwnerPackageName;
-    private int mDeviceId;
-    private @Nullable String mPersistentDeviceId;
+    private final int mDeviceId;
+    private @Nullable final String mPersistentDeviceId;
     // Thou shall not hold the mVirtualDeviceLock over the mInputController calls.
     // Holding the lock can lead to lock inversion with GlobalWindowManagerLock.
     // 1. After display is created the window manager calls into VDM during construction
@@ -145,6 +154,8 @@
     private final IBinder mAppToken;
     private final VirtualDeviceParams mParams;
     @GuardedBy("mVirtualDeviceLock")
+    private final SparseIntArray mDevicePolicies;
+    @GuardedBy("mVirtualDeviceLock")
     private final SparseArray<VirtualDisplayWrapper> mVirtualDisplays = new SparseArray<>();
     private final IVirtualDeviceActivityListener mActivityListener;
     private final IVirtualDeviceSoundEffectListener mSoundEffectListener;
@@ -152,7 +163,7 @@
     @GuardedBy("mVirtualDeviceLock")
     private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>();
     @NonNull
-    private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
+    private final Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
     // The default setting for showing the pointer on new displays.
     @GuardedBy("mVirtualDeviceLock")
     private boolean mDefaultShowPointerIcon = true;
@@ -160,6 +171,9 @@
     @Nullable
     private LocaleList mLocaleList = null;
 
+    @NonNull
+    private final VirtualDevice mPublicVirtualDeviceObject;
+
     private ActivityListener createListenerAdapter() {
         return new ActivityListener() {
 
@@ -259,6 +273,7 @@
         mDeviceId = deviceId;
         mAppToken = token;
         mParams = params;
+        mDevicePolicies = params.getDevicePolicies();
         mDisplayManager = displayManager;
         if (inputController == null) {
             mInputController = new InputController(
@@ -277,6 +292,9 @@
             throw e.rethrowFromSystemServer();
         }
         mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);
+
+        mPublicVirtualDeviceObject = new VirtualDevice(
+                this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
     }
 
     @VisibleForTesting
@@ -306,9 +324,9 @@
         return mAssociationInfo.getDisplayName();
     }
 
-    /** Returns the optional name of the device. */
-    String getDeviceName() {
-        return mParams.getName();
+    /** Returns the public representation of the device. */
+    VirtualDevice getPublicVirtualDeviceObject() {
+        return mPublicVirtualDeviceObject;
     }
 
     /** Returns the locale of the device. */
@@ -318,10 +336,16 @@
         }
     }
 
-    /** Returns the policy specified for this policy type */
+    @Override  // Binder call
     public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
             @VirtualDeviceParams.PolicyType int policyType) {
-        return mParams.getDevicePolicy(policyType);
+        if (Flags.dynamicPolicy()) {
+            synchronized (mVirtualDeviceLock) {
+                return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
+            }
+        } else {
+            return mParams.getDevicePolicy(policyType);
+        }
     }
 
     /** Returns device-specific audio session id for playback. */
@@ -410,15 +434,13 @@
     public void close() {
         super.close_enforcePermission();
         // Remove about-to-be-closed virtual device from the service before butchering it.
-        boolean removed = mService.removeVirtualDevice(mDeviceId);
-        mVirtualDeviceLog.logClosed(mDeviceId, mOwnerUid);
-        mDeviceId = Context.DEVICE_ID_INVALID;
-
-        // Device is already closed.
-        if (!removed) {
+        if (!mService.removeVirtualDevice(mDeviceId)) {
+            // Device is already closed.
             return;
         }
 
+        mVirtualDeviceLog.logClosed(mDeviceId, mOwnerUid);
+
         final long ident = Binder.clearCallingIdentity();
         try {
             VirtualDisplayWrapper[] virtualDisplaysToBeReleased;
@@ -460,6 +482,7 @@
     }
 
     @Override
+    @RequiresPermission(android.Manifest.permission.CAMERA_INJECT_EXTERNAL_CAMERA)
     public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
         mCameraAccessController.blockCameraAccessIfNeeded(runningUids);
         mRunningAppsChangedCallback.accept(runningUids);
@@ -507,6 +530,27 @@
 
     @Override // Binder call
     @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+    public void setDevicePolicy(@VirtualDeviceParams.DynamicPolicyType int policyType,
+            @VirtualDeviceParams.DevicePolicy int devicePolicy) {
+        super.setDevicePolicy_enforcePermission();
+        switch (policyType) {
+            case POLICY_TYPE_RECENTS:
+                synchronized (mVirtualDeviceLock) {
+                    mDevicePolicies.put(policyType, devicePolicy);
+                    for (int i = 0; i < mVirtualDisplays.size(); i++) {
+                        mVirtualDisplays.valueAt(i).getWindowPolicyController()
+                                .setShowInHostDeviceRecents(devicePolicy == DEVICE_POLICY_DEFAULT);
+                    }
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("Device policy " + policyType
+                        + " cannot be changed at runtime. ");
+        }
+    }
+
+    @Override // Binder call
+    @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
         super.createVirtualDpad_enforcePermission();
         Objects.requireNonNull(config);
@@ -718,10 +762,10 @@
         try {
             synchronized (mVirtualDeviceLock) {
                 mDefaultShowPointerIcon = showPointerIcon;
-                for (int i = 0; i < mVirtualDisplays.size(); i++) {
-                    final int displayId = mVirtualDisplays.keyAt(i);
-                    mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
-                }
+            }
+            final int[] displayIds = getDisplayIds();
+            for (int i = 0; i < displayIds.length; ++i) {
+                mInputController.setShowPointerIcon(showPointerIcon, displayIds[i]);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -786,6 +830,7 @@
         mParams.dump(fout, "        ");
         fout.println("    mVirtualDisplayIds: ");
         synchronized (mVirtualDeviceLock) {
+            fout.println("    mDevicePolicies: " + mDevicePolicies);
             for (int i = 0; i < mVirtualDisplays.size(); i++) {
                 fout.println("      " + mVirtualDisplays.keyAt(i));
             }
@@ -797,24 +842,31 @@
 
     private GenericWindowPolicyController createWindowPolicyController(
             @NonNull Set<String> displayCategories) {
-        final GenericWindowPolicyController gwpc =
-                new GenericWindowPolicyController(FLAG_SECURE,
-                        SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
-                        getAllowedUserHandles(),
-                        mParams.getAllowedCrossTaskNavigations(),
-                        mParams.getBlockedCrossTaskNavigations(),
-                        mParams.getAllowedActivities(),
-                        mParams.getBlockedActivities(),
-                        mParams.getDefaultActivityPolicy(),
-                        createListenerAdapter(),
-                        this::onEnteringPipBlocked,
-                        this::onActivityBlocked,
-                        this::onSecureWindowShown,
-                        this::shouldInterceptIntent,
-                        displayCategories,
-                        mParams.getDevicePolicy(
-                                VirtualDeviceParams.POLICY_TYPE_RECENTS)
-                                == VirtualDeviceParams.DEVICE_POLICY_DEFAULT);
+        final boolean activityLaunchAllowedByDefault =
+                mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
+        final boolean crossTaskNavigationAllowedByDefault =
+                mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
+        final boolean showTasksInHostDeviceRecents =
+                mParams.getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
+
+        final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
+                FLAG_SECURE,
+                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+                getAllowedUserHandles(),
+                activityLaunchAllowedByDefault,
+                /*activityPolicyExceptions=*/activityLaunchAllowedByDefault
+                        ? mParams.getBlockedActivities() : mParams.getAllowedActivities(),
+                crossTaskNavigationAllowedByDefault,
+                /*crossTaskNavigationExceptions=*/crossTaskNavigationAllowedByDefault
+                        ? mParams.getBlockedCrossTaskNavigations()
+                        : mParams.getAllowedCrossTaskNavigations(),
+                createListenerAdapter(),
+                this::onEnteringPipBlocked,
+                this::onActivityBlocked,
+                this::onSecureWindowShown,
+                this::shouldInterceptIntent,
+                displayCategories,
+                showTasksInHostDeviceRecents);
         gwpc.registerRunningAppsChangedListener(/* listener= */ this);
         return gwpc;
     }
@@ -830,6 +882,7 @@
                 this, gwpc, packageName);
         gwpc.setDisplayId(displayId);
 
+        boolean showPointer;
         synchronized (mVirtualDeviceLock) {
             if (mVirtualDisplays.contains(displayId)) {
                 gwpc.unregisterRunningAppsChangedListener(this);
@@ -839,11 +892,12 @@
 
             PowerManager.WakeLock wakeLock = createAndAcquireWakeLockForDisplay(displayId);
             mVirtualDisplays.put(displayId, new VirtualDisplayWrapper(callback, gwpc, wakeLock));
+            showPointer = mDefaultShowPointerIcon;
         }
 
         final long token = Binder.clearCallingIdentity();
         try {
-            mInputController.setShowPointerIcon(mDefaultShowPointerIcon, displayId);
+            mInputController.setShowPointerIcon(showPointer, displayId);
             mInputController.setPointerAcceleration(1f, displayId);
             mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false,
                     displayId);
@@ -869,6 +923,7 @@
         }
     }
 
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
     private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
         Intent intent = BlockedAppStreamingActivity.createIntent(
                 activityInfo, mAssociationInfo.getDisplayName());
@@ -950,6 +1005,7 @@
         }
     }
 
+    @SuppressWarnings("AndroidFrameworkRequiresPermission")
     private void checkVirtualInputDeviceDisplayIdAssociation(int displayId) {
         if (mContext.checkCallingPermission(android.Manifest.permission.INJECT_EVENTS)
                     == PackageManager.PERMISSION_GRANTED) {
@@ -982,14 +1038,15 @@
         return mOwnerUid;
     }
 
-    ArraySet<Integer> getDisplayIds() {
+    @Override  // Binder call
+    public int[] getDisplayIds() {
         synchronized (mVirtualDeviceLock) {
             final int size = mVirtualDisplays.size();
-            ArraySet<Integer> arraySet = new ArraySet<>(size);
+            int[] displayIds = new int[size];
             for (int i = 0; i < size; i++) {
-                arraySet.append(mVirtualDisplays.keyAt(i));
+                displayIds[i] = mVirtualDisplays.keyAt(i);
             }
-            return arraySet;
+            return displayIds;
         }
     }
 
@@ -1031,8 +1088,8 @@
      */
     void showToastWhereUidIsRunning(int uid, String text, @Toast.Duration int duration,
             Looper looper) {
-        ArrayList<Integer> displayIdsForUid = getDisplayIdsWhereUidIsRunning(uid);
-        if (displayIdsForUid.isEmpty()) {
+        IntArray displayIdsForUid = getDisplayIdsWhereUidIsRunning(uid);
+        if (displayIdsForUid.size() == 0) {
             return;
         }
         DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
@@ -1045,8 +1102,8 @@
         }
     }
 
-    private ArrayList<Integer> getDisplayIdsWhereUidIsRunning(int uid) {
-        ArrayList<Integer> displayIdsForUid = new ArrayList<>();
+    private IntArray getDisplayIdsWhereUidIsRunning(int uid) {
+        IntArray displayIdsForUid = new IntArray();
         synchronized (mVirtualDeviceLock) {
             for (int i = 0; i < mVirtualDisplays.size(); i++) {
                 if (mVirtualDisplays.valueAt(i).getWindowPolicyController().containsUid(uid)) {
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 7429fbe..cfe56e9 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -23,17 +23,20 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.app.ActivityOptions;
 import android.companion.AssociationInfo;
 import android.companion.CompanionDeviceManager;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.IVirtualDeviceListener;
 import android.companion.virtual.IVirtualDeviceManager;
 import android.companion.virtual.IVirtualDeviceSoundEffectListener;
 import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceParams;
+import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.content.AttributionSource;
 import android.content.Context;
@@ -47,6 +50,7 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
@@ -68,6 +72,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
@@ -75,6 +80,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 
 @SuppressLint("LongLogTag")
@@ -95,11 +101,15 @@
     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 final RemoteCallbackList<IVirtualDeviceListener> mVirtualDeviceListeners =
+            new RemoteCallbackList<>();
+
     /**
      * Mapping from device IDs to virtual devices.
      */
@@ -222,6 +232,17 @@
             mVirtualDevices.remove(deviceId);
         }
 
+        if (Flags.vdmPublicApis()) {
+            mVirtualDeviceListeners.broadcast(listener -> {
+                try {
+                    listener.onVirtualDeviceClosed(deviceId);
+                } catch (RemoteException e) {
+                    Slog.i(TAG, "Failed to invoke onVirtualDeviceClosed listener: "
+                            + e.getMessage());
+                }
+            });
+        }
+
         Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
         i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId);
         i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -240,6 +261,7 @@
         return true;
     }
 
+    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     private void syncVirtualDevicesToCdmAssociations(List<AssociationInfo> associations) {
         Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>();
         synchronized (mVirtualDeviceManagerLock) {
@@ -265,6 +287,7 @@
         }
     }
 
+    @RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
     private void registerCdmAssociationListener() {
         final CompanionDeviceManager cdm = getContext().getSystemService(
                 CompanionDeviceManager.class);
@@ -272,6 +295,7 @@
                 mCdmAssociationListener);
     }
 
+    @RequiresPermission(android.Manifest.permission.MANAGE_COMPANION_DEVICES)
     private void unregisterCdmAssociationListener() {
         final CompanionDeviceManager cdm = getContext().getSystemService(
                 CompanionDeviceManager.class);
@@ -323,6 +347,15 @@
                 @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) {
             createVirtualDevice_enforcePermission();
             attributionSource.enforceCallingUid();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (Flags.moreLogs()) {
+                    Slog.i(TAG, "Creating VirtualDevice");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
             final int callingUid = getCallingUid();
             final String packageName = attributionSource.getPackageName();
             if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
@@ -361,6 +394,17 @@
                 }
                 mVirtualDevices.put(deviceId, virtualDevice);
             }
+
+            if (Flags.vdmPublicApis()) {
+                mVirtualDeviceListeners.broadcast(listener -> {
+                    try {
+                        listener.onVirtualDeviceCreated(deviceId);
+                    } catch (RemoteException e) {
+                        Slog.i(TAG, "Failed to invoke onVirtualDeviceCreated listener: "
+                                + e.getMessage());
+                    }
+                });
+            }
             return virtualDevice;
         }
 
@@ -400,14 +444,31 @@
             synchronized (mVirtualDeviceManagerLock) {
                 for (int i = 0; i < mVirtualDevices.size(); i++) {
                     final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
-                    virtualDevices.add(
-                            new VirtualDevice(device.getDeviceId(), device.getPersistentDeviceId(),
-                                    device.getDeviceName()));
+                    virtualDevices.add(device.getPublicVirtualDeviceObject());
                 }
             }
             return virtualDevices;
         }
 
+        @Override // Binder call
+        public VirtualDevice getVirtualDevice(int deviceId) {
+            VirtualDeviceImpl device;
+            synchronized (mVirtualDeviceManagerLock) {
+                device = mVirtualDevices.get(deviceId);
+            }
+            return device == null ? null : device.getPublicVirtualDeviceObject();
+        }
+
+        @Override // Binder call
+        public void registerVirtualDeviceListener(IVirtualDeviceListener listener) {
+            mVirtualDeviceListeners.register(listener);
+        }
+
+        @Override // Binder call
+        public void unregisterVirtualDeviceListener(IVirtualDeviceListener listener) {
+            mVirtualDeviceListeners.unregister(listener);
+        }
+
         @Override // BinderCall
         @VirtualDeviceParams.DevicePolicy
         public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
@@ -690,7 +751,9 @@
             synchronized (mVirtualDeviceManagerLock) {
                 virtualDevice = mVirtualDevices.get(deviceId);
             }
-            return virtualDevice == null ? new ArraySet<>() : virtualDevice.getDisplayIds();
+            return virtualDevice == null ? new ArraySet<>()
+                    : Arrays.stream(virtualDevice.getDisplayIds()).boxed()
+                            .collect(Collectors.toCollection(ArraySet::new));
         }
 
         @Override
diff --git a/services/companion/java/com/android/server/companion/virtual/flags.aconfig b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
index 4fe4c87..6297e91 100644
--- a/services/companion/java/com/android/server/companion/virtual/flags.aconfig
+++ b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
@@ -1,3 +1,5 @@
+# OLD PACKAGE, DO NOT USE: Prefer `flags.aconfig` in core/java/android/companion/virtual
+# (or other custom files) to define your flags
 package: "com.android.server.companion.virtual"
 
 flag {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 557e4ac..838aae8 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1409,4 +1409,10 @@
      */
     public abstract boolean isPackageQuarantined(@NonNull String packageName,
             @UserIdInt int userId);
+
+    /**
+     * Return a list of all historical install sessions for the given user.
+     */
+    public abstract ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(
+            int userId);
 }
diff --git a/services/core/java/com/android/server/LogMteState.java b/services/core/java/com/android/server/LogMteState.java
index 410dd83..ec0492b 100644
--- a/services/core/java/com/android/server/LogMteState.java
+++ b/services/core/java/com/android/server/LogMteState.java
@@ -16,11 +16,12 @@
 
 package com.android.server;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
 import android.app.StatsManager;
 import android.content.Context;
 import android.util.StatsEvent;
 
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.FrameworkStatsLog;
 
@@ -32,7 +33,7 @@
                 .setPullAtomCallback(
                         FrameworkStatsLog.MTE_STATE,
                         null, // use default PullAtomMetadata values
-                        BackgroundThread.getExecutor(),
+                        DIRECT_EXECUTOR,
                         new StatsManager.StatsPullAtomCallback() {
                             @Override
                             public int onPullAtom(int atomTag, List<StatsEvent> data) {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3fd6fe8..9bab261 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -78,11 +78,14 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import sun.misc.Unsafe;
+
 /**
  * <p>PinnerService pins important files for key processes in memory.</p>
  * <p>Files to pin are specified in the config_defaultPinnerServiceFiles
@@ -150,6 +153,11 @@
     @GuardedBy("this")
     private ArraySet<Integer> mPinKeys;
 
+    private static final long MAX_ANON_SIZE = 2L * (1L << 30); // 2GB
+    private long mPinAnonSize;
+    private long mPinAnonAddress;
+    private long mCurrentlyPinnedAnonSize;
+
     // Resource-configured pinner flags;
     private final boolean mConfiguredToPinCamera;
     private final boolean mConfiguredToPinHome;
@@ -550,6 +558,11 @@
             pinKeys.add(KEY_ASSISTANT);
         }
 
+        mPinAnonSize = DeviceConfig.getLong(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+                "pin_anon_size",
+                SystemProperties.getLong("pinner.pin_anon_size", 0));
+        mPinAnonSize = Math.max(0, Math.min(mPinAnonSize, MAX_ANON_SIZE));
+
         return pinKeys;
     }
 
@@ -589,6 +602,7 @@
             int key = currentPinKeys.valueAt(i);
             pinApp(key, userHandle, true /* force */);
         }
+        pinAnonRegion();
     }
 
     /**
@@ -673,6 +687,64 @@
     }
 
     /**
+     * Pin an empty anonymous region. This should only be used for ablation experiments.
+     */
+    private void pinAnonRegion() {
+        if (mPinAnonSize == 0) {
+            return;
+        }
+        long alignedPinSize = mPinAnonSize;
+        if (alignedPinSize % PAGE_SIZE != 0) {
+            alignedPinSize -= alignedPinSize % PAGE_SIZE;
+            Slog.e(TAG, "pinAnonRegion: aligning size to " + alignedPinSize);
+        }
+        if (mPinAnonAddress != 0
+                && mCurrentlyPinnedAnonSize != alignedPinSize) {
+            unpinAnonRegion();
+        }
+        long address = 0;
+        try {
+            address = Os.mmap(0, alignedPinSize,
+                    OsConstants.PROT_READ | OsConstants.PROT_WRITE,
+                    OsConstants.MAP_PRIVATE | OsConstants.MAP_ANONYMOUS,
+                    new FileDescriptor(), /*offset=*/0);
+
+            Unsafe tempUnsafe = null;
+            Class<sun.misc.Unsafe> clazz = sun.misc.Unsafe.class;
+            for (java.lang.reflect.Field f : clazz.getDeclaredFields()) {
+                f.setAccessible(true);
+                Object obj = f.get(null);
+                if (clazz.isInstance(obj)) {
+                    tempUnsafe = clazz.cast(obj);
+                }
+            }
+            if (tempUnsafe == null) {
+                throw new Exception("Couldn't get Unsafe");
+            }
+            Method setMemory = clazz.getMethod("setMemory", long.class, long.class, byte.class);
+            setMemory.invoke(tempUnsafe, address, alignedPinSize, (byte) 1);
+            Os.mlock(address, alignedPinSize);
+            mCurrentlyPinnedAnonSize = alignedPinSize;
+            mPinAnonAddress = address;
+            address = -1;
+            Slog.e(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize);
+        } catch (Exception ex) {
+            Slog.e(TAG, "Could not pin anon region of size " + alignedPinSize, ex);
+            return;
+        } finally {
+            if (address >= 0) {
+                safeMunmap(address, alignedPinSize);
+            }
+        }
+    }
+
+    private void unpinAnonRegion() {
+        if (mPinAnonAddress != 0) {
+            safeMunmap(mPinAnonAddress, mCurrentlyPinnedAnonSize);
+        }
+    }
+
+    /**
      * @return The maximum amount of bytes to be pinned for an app of type {@code key}.
      */
     private int getSizeLimitForKey(@AppKey int key) {
@@ -1083,6 +1155,9 @@
                         totalSize += pf.bytesPinned;
                     }
                 }
+                if (mPinAnonAddress != 0) {
+                    pw.format("Pinned anon region: %s\n", mCurrentlyPinnedAnonSize);
+                }
                 pw.format("Total size: %s\n", totalSize);
                 pw.println();
                 if (!mPendingRepin.isEmpty()) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 4d249ab..a787644 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -32,6 +32,7 @@
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.IInstalld.IFsveritySetupAuthToken;
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
 import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
@@ -678,6 +679,7 @@
     private static final int H_VOLUME_STATE_CHANGED = 15;
     private static final int H_CLOUD_MEDIA_PROVIDER_CHANGED = 16;
     private static final int H_SECURE_KEYGUARD_STATE_CHANGED = 17;
+    private static final int H_REMOUNT_VOLUMES_ON_MOVE = 18;
 
     class StorageManagerServiceHandler extends Handler {
         public StorageManagerServiceHandler(Looper looper) {
@@ -833,6 +835,10 @@
                     }
                     break;
                 }
+                case H_REMOUNT_VOLUMES_ON_MOVE: {
+                    remountVolumesForRunningUsersOnMove();
+                    break;
+                }
             }
         }
     }
@@ -1286,6 +1292,44 @@
         }
     }
 
+    /**
+     * This method informs vold and storaged that the user has stopped and started whenever move
+     * storage is performed. This ensures that the correct emulated volumes are mounted for the
+     * users other than the current user. This solves an edge case wherein the correct emulated
+     * volumes are not mounted, this will cause the media data to be still stored on internal
+     * storage whereas the data should be stored in the adopted primary storage. This method stops
+     * the users at vold first which will remove the old volumes which and starts the users at vold
+     * which will reattach the correct volumes. This does not performs a full reset as full reset
+     * clears every state from vold and SMS {@link #resetIfRebootedAndConnected} which is expensive
+     * and causes instability.
+     */
+    private void remountVolumesForRunningUsersOnMove() {
+        // Do not want to hold the lock for long
+        final List<Integer> unlockedUsers = new ArrayList<>();
+        synchronized (mLock) {
+            for (int userId : mSystemUnlockedUsers) {
+                if (userId == mCurrentUserId) continue;
+                unlockedUsers.add(userId);
+            }
+        }
+        for (Integer userId : unlockedUsers) {
+            try {
+                mVold.onUserStopped(userId);
+                mStoraged.onUserStopped(userId);
+            } catch (Exception e) {
+                Slog.wtf(TAG, e);
+            }
+        }
+        for (Integer userId : unlockedUsers) {
+            try {
+                mVold.onUserStarted(userId);
+                mStoraged.onUserStarted(userId);
+            } catch (Exception e) {
+                Slog.wtf(TAG, e);
+            }
+        }
+    }
+
     private boolean supportsBlockCheckpoint() throws RemoteException {
         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
         return mVold.supportsBlockCheckpoint();
@@ -1820,6 +1864,7 @@
 
             mPrimaryStorageUuid = mMoveTargetUuid;
             writeSettingsLocked();
+            mHandler.obtainMessage(H_REMOUNT_VOLUMES_ON_MOVE).sendToTarget();
         }
 
         if (PackageManager.isMoveStatusFinished(status)) {
@@ -4640,7 +4685,7 @@
                 pw.print(") total size: ");
                 pw.print(pair.second);
                 pw.print(" (");
-                pw.print(DataUnit.MEBIBYTES.toBytes(pair.second));
+                pw.print(pair.second / DataUnit.MEBIBYTES.toBytes(1L));
                 pw.println(" MiB)");
             }
 
@@ -4950,5 +4995,24 @@
             }
         }
 
+        @Override
+        public IFsveritySetupAuthToken createFsveritySetupAuthToken(ParcelFileDescriptor authFd,
+                int appUid, @UserIdInt int userId) throws IOException {
+            try {
+                return mInstaller.createFsveritySetupAuthToken(authFd, appUid, userId);
+            } catch (Installer.InstallerException e) {
+                throw new IOException(e);
+            }
+        }
+
+        @Override
+        public int enableFsverity(IFsveritySetupAuthToken authToken, String filePath,
+                String packageName) throws IOException {
+            try {
+                return mInstaller.enableFsverity(authToken, filePath, packageName);
+            } catch (Installer.InstallerException e) {
+                throw new IOException(e);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 03022b0..cd0a9d2 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -74,6 +74,15 @@
         {
             "name": "CtsVcnTestCases",
             "file_patterns": ["VcnManagementService\\.java"]
+        },
+        {
+            "name": "FrameworksNetTests",
+            "options": [
+                {
+                    "exclude-annotation": "com.android.testutils.SkipPresubmit"
+                }
+            ],
+            "file_patterns": ["VpnManagerService\\.java"]
         }
     ],
     "presubmit-large": [
@@ -91,6 +100,21 @@
                 }
             ],
             "file_patterns": ["ClipboardService\\.java"]
+        },
+        {
+            "name": "CtsHostsideNetworkTests",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "com.android.testutils.SkipPresubmit"
+                }
+            ],
+            "file_patterns": ["VpnManagerService\\.java"]
         }
     ]
 }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 6baae4b..e17424b 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -937,7 +937,7 @@
                         mActivity.addErrorToDropBox(
                                 dropboxTag, null, "system_server", null, null, null,
                                 null, report.toString(), stack, null, null, null,
-                                errorId);
+                                errorId, null);
                     }
                 }
             };
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c4816fb..0d265a0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2115,6 +2115,34 @@
         mVoiceInteractionManagerProvider = provider;
     }
 
+    /**
+     * Represents volatile states associated with a Dropbox entry.
+     * <p>
+     * These states, such as the process frozen state, can change quickly over time and thus
+     * should be captured as soon as possible to ensure accurate state. If a state is undefined,
+     * it means that the state was not read early and a fallback value can be used.
+     * </p>
+     */
+    static class VolatileDropboxEntryStates {
+        private final Boolean mIsProcessFrozen;
+
+        private VolatileDropboxEntryStates(Boolean frozenState) {
+            this.mIsProcessFrozen = frozenState;
+        }
+
+        public static VolatileDropboxEntryStates withProcessFrozenState(boolean frozenState) {
+            return new VolatileDropboxEntryStates(frozenState);
+        }
+
+        public static VolatileDropboxEntryStates emptyVolatileDropboxEnytyStates() {
+            return new VolatileDropboxEntryStates(null);
+        }
+
+        public Boolean isProcessFrozen() {
+            return mIsProcessFrozen;
+        }
+    }
+
     static class MemBinder extends Binder {
         ActivityManagerService mActivityManagerService;
         private final PriorityDump.PriorityDumper mPriorityDumper =
@@ -3503,6 +3531,12 @@
     @Override
     public boolean clearApplicationUserData(final String packageName, boolean keepState,
             final IPackageDataObserver observer, int userId) {
+        return clearApplicationUserData(packageName, keepState, /*isRestore=*/ false, observer,
+                userId);
+    }
+
+    private boolean clearApplicationUserData(final String packageName, boolean keepState,
+            boolean isRestore, final IPackageDataObserver observer, int userId) {
         enforceNotIsolatedCaller("clearApplicationUserData");
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
@@ -3597,6 +3631,9 @@
                         intent.putExtra(Intent.EXTRA_UID,
                                 (appInfo != null) ? appInfo.uid : INVALID_UID);
                         intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
+                        if (isRestore) {
+                            intent.putExtra(Intent.EXTRA_IS_RESTORE, true);
+                        }
                         if (isInstantApp) {
                             intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
                         }
@@ -3815,15 +3852,16 @@
 
     @Override
     public void forceStopPackage(final String packageName, int userId) {
-        forceStopPackage(packageName, userId, /*flags=*/ 0);
+        forceStopPackage(packageName, userId, /*flags=*/ 0, null);
     }
 
     @Override
     public void forceStopPackageEvenWhenStopping(final String packageName, int userId) {
-        forceStopPackage(packageName, userId, ActivityManager.FLAG_OR_STOPPED);
+        forceStopPackage(packageName, userId, ActivityManager.FLAG_OR_STOPPED, null);
     }
 
-    private void forceStopPackage(final String packageName, int userId, int userRunningFlags) {
+    private void forceStopPackage(final String packageName, int userId, int userRunningFlags,
+            String reason) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: forceStopPackage() from pid="
@@ -3868,7 +3906,8 @@
                                 + packageName + ": " + e);
                     }
                     if (mUserController.isUserRunning(user, userRunningFlags)) {
-                        forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
+                        forceStopPackageLocked(packageName, pkgUid,
+                                reason == null ? ("from pid " + callingPid) : reason);
                         finishForceStopPackageLocked(packageName, pkgUid);
                     }
                 }
@@ -5407,6 +5446,19 @@
                 intent = new Intent(Intent.ACTION_MAIN);
             }
             try {
+                if (allowlistToken != null) {
+                    final int callingUid = Binder.getCallingUid();
+                    final String packageName;
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        packageName = AppGlobals.getPackageManager().getNameForUid(callingUid);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    Slog.wtf(TAG, "Send a non-null allowlistToken to a non-PI target."
+                            + " Calling package: " + packageName + "; intent: " + intent
+                            + "; options: " + options);
+                }
                 target.send(code, intent, resolvedType, allowlistToken, null,
                         requiredPermission, options);
             } catch (RemoteException e) {
@@ -8941,7 +8993,7 @@
 
         addErrorToDropBox(
                 eventType, r, processName, null, null, null, null, null, null, crashInfo,
-                new Float(loadingProgress), incrementalMetrics, null);
+                new Float(loadingProgress), incrementalMetrics, null, null);
 
         // For GWP-ASan recoverable crashes, don't make the app crash (the whole point of
         // 'recoverable' is that the app doesn't crash). Normally, for nonrecoreable native crashes,
@@ -9052,7 +9104,7 @@
 
         final StringBuilder sb = new StringBuilder(1024);
         synchronized (sb) {
-            appendDropBoxProcessHeaders(process, processName, sb);
+            appendDropBoxProcessHeaders(process, processName, null, sb);
             sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
             sb.append("System-App: ").append(isSystemApp).append("\n");
             sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n");
@@ -9155,7 +9207,7 @@
                 callingPid, (r != null) ? r.getProcessClassEnum() : 0);
 
         addErrorToDropBox("wtf", r, processName, null, null, null, tag, null, null, crashInfo,
-                null, null, null);
+                null, null, null, null);
 
         return r;
     }
@@ -9180,7 +9232,7 @@
         for (Pair<String, ApplicationErrorReport.CrashInfo> p = list.poll();
                 p != null; p = list.poll()) {
             addErrorToDropBox("wtf", proc, "system_server", null, null, null, p.first, null, null,
-                    p.second, null, null, null);
+                    p.second, null, null, null, null);
         }
     }
 
@@ -9203,7 +9255,7 @@
      * to append various headers to the dropbox log text.
      */
     void appendDropBoxProcessHeaders(ProcessRecord process, String processName,
-            final StringBuilder sb) {
+            final VolatileDropboxEntryStates volatileStates, final StringBuilder sb) {
         // Watchdog thread ends up invoking this function (with
         // a null ProcessRecord) to add the stack file to dropbox.
         // Do not acquire a lock on this (am) in such cases, as it
@@ -9222,7 +9274,12 @@
             sb.append("PID: ").append(process.getPid()).append("\n");
             sb.append("UID: ").append(process.uid).append("\n");
             if (process.mOptRecord != null) {
-                sb.append("Frozen: ").append(process.mOptRecord.isFrozen()).append("\n");
+                // Use 'isProcessFrozen' from 'volatileStates' if it'snon-null (present),
+                // otherwise use 'isFrozen' from 'mOptRecord'.
+                sb.append("Frozen: ").append(
+                    (volatileStates != null && volatileStates.isProcessFrozen() != null)
+                    ? volatileStates.isProcessFrozen() : process.mOptRecord.isFrozen()
+                ).append("\n");
             }
             int flags = process.info.flags;
             final IPackageManager pm = AppGlobals.getPackageManager();
@@ -9335,7 +9392,7 @@
             String subject, final String report, final File dataFile,
             final ApplicationErrorReport.CrashInfo crashInfo,
             @Nullable Float loadingProgress, @Nullable IncrementalMetrics incrementalMetrics,
-            @Nullable UUID errorId) {
+            @Nullable UUID errorId, @Nullable VolatileDropboxEntryStates volatileStates) {
         // NOTE -- this must never acquire the ActivityManagerService lock,
         // otherwise the watchdog may be prevented from resetting the system.
 
@@ -9357,7 +9414,7 @@
         if (rateLimitResult.shouldRateLimit()) return;
 
         final StringBuilder sb = new StringBuilder(1024);
-        appendDropBoxProcessHeaders(process, processName, sb);
+        appendDropBoxProcessHeaders(process, processName, volatileStates, sb);
         if (process != null) {
             sb.append("Foreground: ")
                     .append(process.isInterestingToUserLocked() ? "Yes" : "No")
@@ -14856,8 +14913,8 @@
                                     Intent.EXTRA_QUARANTINED, false);
                             if (suspended && quarantined && packageNames != null) {
                                 for (int i = 0; i < packageNames.length; i++) {
-                                    forceStopPackageLocked(packageNames[i], -1, false, true, true,
-                                            false, false, userId, "suspended");
+                                    forceStopPackage(packageNames[i], userId,
+                                            ActivityManager.FLAG_OR_STOPPED, "quarantined");
                                 }
                             }
 
@@ -18981,6 +19038,13 @@
             return mAppProfiler.mCachedAppsWatermarkData.getCachedAppsHighWatermarkStats(
                     atomTag, resetAfterPull);
         }
+
+        @Override
+        public boolean clearApplicationUserData(final String packageName, boolean keepState,
+                boolean isRestore, final IPackageDataObserver observer, int userId) {
+            return ActivityManagerService.this.clearApplicationUserData(packageName, keepState,
+                    isRestore, observer, userId);
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java
index e7f4bf9..46e5523 100644
--- a/services/core/java/com/android/server/am/AppProfiler.java
+++ b/services/core/java/com/android/server/am/AppProfiler.java
@@ -1843,7 +1843,8 @@
         dropBuilder.append(catSw.toString());
         FrameworkStatsLog.write(FrameworkStatsLog.LOW_MEM_REPORTED);
         mService.addErrorToDropBox("lowmem", null, "system_server", null,
-                null, null, tag.toString(), dropBuilder.toString(), null, null, null, null, null);
+                null, null, tag.toString(), dropBuilder.toString(), null, null, null, null, null,
+                null);
         synchronized (mService) {
             long now = SystemClock.uptimeMillis();
             if (mLastMemUsageReportTime < now) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 610b8af..2249607 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -27,9 +27,12 @@
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
 import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
 import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.annotation.RequiresNoPermission;
+import android.annotation.SuppressLint;
 import android.app.StatsManager;
 import android.app.usage.NetworkStatsManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -81,6 +84,7 @@
 import android.os.health.HealthStatsWriter;
 import android.os.health.UidHealthStats;
 import android.power.PowerStatsInternal;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.ModemActivityInfo;
@@ -94,7 +98,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BinderCallsStats;
 import com.android.internal.os.CpuScalingPolicies;
 import com.android.internal.os.CpuScalingPolicyReader;
@@ -174,6 +177,7 @@
                     .replaceWith("?");
     private static final int MAX_LOW_POWER_STATS_SIZE = 32768;
     private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
+    private static final String MIN_CONSUMED_POWER_THRESHOLD_KEY = "min_consumed_power_threshold";
     private static final String EMPTY = "Empty";
 
     private final HandlerThread mHandlerThread;
@@ -844,15 +848,15 @@
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(), pullAtomCallback);
+                DIRECT_EXECUTOR, pullAtomCallback);
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET_USING_POWER_PROFILE_MODEL,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(), pullAtomCallback);
+                DIRECT_EXECUTOR, pullAtomCallback);
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(), pullAtomCallback);
+                DIRECT_EXECUTOR, pullAtomCallback);
     }
 
     /** StatsPullAtomCallback for pulling BatteryUsageStats data. */
@@ -862,12 +866,17 @@
             final BatteryUsageStats bus;
             switch (atomTag) {
                 case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET:
+                    @SuppressLint("MissingPermission")
+                    final double minConsumedPowerThreshold =
+                            DeviceConfig.getFloat(DeviceConfig.NAMESPACE_BATTERY_STATS,
+                                    MIN_CONSUMED_POWER_THRESHOLD_KEY, 0);
                     final BatteryUsageStatsQuery querySinceReset =
                             new BatteryUsageStatsQuery.Builder()
                                     .setMaxStatsAgeMs(0)
                                     .includeProcessStateData()
                                     .includeVirtualUids()
                                     .includePowerModels()
+                                    .setMinConsumedPowerThreshold(minConsumedPowerThreshold)
                                     .build();
                     bus = getBatteryUsageStats(List.of(querySinceReset)).get(0);
                     break;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 1a58556..5fa0ffa 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1514,7 +1514,7 @@
                     mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG,
                         pid,
                         (int) Math.min(opt.getFreezeUnfreezeTime() - freezeTime, Integer.MAX_VALUE),
-                        new Pair<String, Integer>(app.processName, reason)));
+                        new Pair<ProcessRecord, Integer>(app, reason)));
         }
     }
 
@@ -2159,11 +2159,12 @@
                 case REPORT_UNFREEZE_MSG: {
                     int pid = msg.arg1;
                     int frozenDuration = msg.arg2;
-                    Pair<String, Integer> obj = (Pair<String, Integer>) msg.obj;
-                    String processName = obj.first;
+                    Pair<ProcessRecord, Integer> obj = (Pair<ProcessRecord, Integer>) msg.obj;
+                    ProcessRecord app = obj.first;
+                    String processName = app.processName;
                     int reason = obj.second;
 
-                    reportUnfreeze(pid, frozenDuration, processName, reason);
+                    reportUnfreeze(app, pid, frozenDuration, processName, reason);
                 } break;
                 case UID_FROZEN_STATE_CHANGED_MSG: {
                     final boolean frozen = (msg.arg1 == 1);
@@ -2358,10 +2359,11 @@
             }
         }
 
-        private void reportUnfreeze(int pid, int frozenDuration, String processName,
-                @UnfreezeReason int reason) {
+        private void reportUnfreeze(ProcessRecord app, int pid, int frozenDuration,
+                String processName, @UnfreezeReason int reason) {
 
             EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName, reason);
+            app.onProcessUnfrozen();
 
             // See above for why we're not taking mPhenotypeFlagLock here
             if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 9219623..095d907 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -1975,9 +1975,10 @@
         return mProviderMap.dumpProviderProto(fd, pw, name, args);
     }
 
-    private Boolean isAuthorityRedirectedForCloneProfileCached(String auth) {
+    private boolean isAuthorityRedirectedForCloneProfileCached(String auth) {
         if (mCloneProfileAuthorityRedirectionCache.containsKey(auth)) {
-            return mCloneProfileAuthorityRedirectionCache.get(auth);
+            final Boolean retVal = mCloneProfileAuthorityRedirectionCache.get(auth);
+            return retVal == null ? false : retVal.booleanValue();
         } else {
             boolean isAuthRedirected = isAuthorityRedirectedForCloneProfile(auth);
             mCloneProfileAuthorityRedirectionCache.put(auth, isAuthRedirected);
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 09df277..40b1de6 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -297,6 +297,7 @@
 
         ArrayList<Integer> firstPids = new ArrayList<>(5);
         SparseBooleanArray lastPids = new SparseBooleanArray(20);
+        ActivityManagerService.VolatileDropboxEntryStates volatileDropboxEntriyStates = null;
 
         mApp.getWindowProcessController().appEarlyNotResponding(annotation, () -> {
             latencyTracker.waitingOnAMSLockStarted();
@@ -343,6 +344,9 @@
             synchronized (mProcLock) {
                 latencyTracker.waitingOnProcLockEnded();
                 setNotResponding(true);
+                volatileDropboxEntriyStates =
+                        ActivityManagerService.VolatileDropboxEntryStates
+                                .withProcessFrozenState(mApp.mOptRecord.isFrozen());
             }
 
             // Log the ANR to the event log.
@@ -620,7 +624,8 @@
                 ? (ProcessRecord) parentProcess.mOwner : null;
         mService.addErrorToDropBox("anr", mApp, mApp.processName, activityShortComponentName,
                 parentShortComponentName, parentPr, null, report.toString(), tracesFile,
-                null, new Float(loadingProgress), incrementalMetrics, errorId);
+                null, new Float(loadingProgress), incrementalMetrics, errorId,
+                volatileDropboxEntriyStates);
 
         if (mApp.getWindowProcessController().appNotResponding(info.toString(),
                 () -> {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 97fb0e7..3d11c68 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -5643,7 +5643,7 @@
             if (logToDropbox) {
                 final long now = SystemClock.elapsedRealtime();
                 final StringBuilder sb = new StringBuilder();
-                mService.appendDropBoxProcessHeaders(app, app.processName, sb);
+                mService.appendDropBoxProcessHeaders(app, app.processName, null, sb);
                 sb.append("Reason: " + reason).append("\n");
                 sb.append("Requester UID: " + requester).append("\n");
                 dbox.addText(DROPBOX_TAG_IMPERCEPTIBLE_KILL, sb.toString());
diff --git a/services/core/java/com/android/server/am/ProcessProfileRecord.java b/services/core/java/com/android/server/am/ProcessProfileRecord.java
index 5ad49a4..db74f1a 100644
--- a/services/core/java/com/android/server/am/ProcessProfileRecord.java
+++ b/services/core/java/com/android/server/am/ProcessProfileRecord.java
@@ -225,6 +225,32 @@
         mBaseProcessTracker = baseProcessTracker;
     }
 
+    void onProcessFrozen() {
+        synchronized (mService.mProcessStats.mLock) {
+            final ProcessState tracker = mBaseProcessTracker;
+            if (tracker != null) {
+                final PackageList pkgList = mApp.getPkgList();
+                final long now = SystemClock.uptimeMillis();
+                synchronized (pkgList) {
+                    tracker.onProcessFrozen(now, pkgList.getPackageListLocked());
+                }
+            }
+        }
+    }
+
+    void onProcessUnfrozen() {
+        synchronized (mService.mProcessStats.mLock) {
+            final ProcessState tracker = mBaseProcessTracker;
+            if (tracker != null) {
+                final PackageList pkgList = mApp.getPkgList();
+                final long now = SystemClock.uptimeMillis();
+                synchronized (pkgList) {
+                    tracker.onProcessUnfrozen(now, pkgList.getPackageListLocked());
+                }
+            }
+        }
+    }
+
     void onProcessActive(IApplicationThread thread, ProcessStatsService tracker) {
         if (mThread == null) {
             synchronized (mProfilerLock) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e2edd8a..cfbb5a5 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1359,6 +1359,15 @@
         return false;
     }
 
+    void onProcessFrozen() {
+        mProfile.onProcessFrozen();
+    }
+
+    void onProcessUnfrozen() {
+        mProfile.onProcessUnfrozen();
+    }
+
+
     /*
      *  Delete all packages from list except the package indicated in info
      */
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 36b8283..bbda952 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -117,20 +117,21 @@
     // All the aconfig flags under the listed DeviceConfig scopes will be synced to native level.
     @VisibleForTesting
     static final String[] sDeviceConfigAconfigScopes = new String[] {
-      "core_experiments_team_internal",
-      "camera_platform",
-      "power",
-      "vibrator",
-      "haptics",
-      "text",
-      "arc_next",
-      "test_suites",
-      "hardware_backed_security_mainline",
-      "threadnetwork",
-      "media_solutions",
-      "responsible_apis",
-      "rust",
-      "pixel_biometrics",
+        "biometrics_framework",
+        "core_experiments_team_internal",
+        "camera_platform",
+        "power",
+        "vibrator",
+        "haptics",
+        "text",
+        "arc_next",
+        "test_suites",
+        "hardware_backed_security_mainline",
+        "threadnetwork",
+        "media_solutions",
+        "responsible_apis",
+        "rust",
+        "pixel_biometrics",
     };
 
     private final String[] mGlobalSettings;
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 81397b4..905589f 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -25,6 +25,7 @@
 import static com.android.internal.R.styleable.GameModeConfig_allowGameFpsOverride;
 import static com.android.internal.R.styleable.GameModeConfig_supportsBatteryGameMode;
 import static com.android.internal.R.styleable.GameModeConfig_supportsPerformanceGameMode;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -2087,17 +2088,17 @@
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.GAME_MODE_INFO,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 this::onPullAtom);
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.GAME_MODE_CONFIGURATION,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 this::onPullAtom);
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.GAME_MODE_LISTENER,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 this::onPullAtom);
     }
 
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index dcc36bc..0ded75a 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -199,28 +199,18 @@
             @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
             @AppOpsManager.AttributionFlags
                     int attributionFlags, int attributionChainId) throws RemoteException {
-        started(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
-                uidState, flags, /*triggerCallbackIfNeeded*/ true, attributionFlags,
-                attributionChainId);
-    }
-
-    private void started(@NonNull IBinder clientId, int proxyUid,
-            @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
-            @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
-            boolean triggerCallbackIfNeeded, @AppOpsManager.AttributionFlags int attributionFlags,
-            int attributionChainId) throws RemoteException {
         startedOrPaused(clientId, proxyUid, proxyPackageName,
-                proxyAttributionTag, uidState, flags, triggerCallbackIfNeeded,
-                /*triggerCallbackIfNeeded*/ true, attributionFlags, attributionChainId);
+                proxyAttributionTag, uidState, flags, /* triggeredByUidStateChange */ false,
+                /* isStarted */ true, attributionFlags, attributionChainId);
     }
 
     @SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
     private void startedOrPaused(@NonNull IBinder clientId, int proxyUid,
             @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
             @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
-            boolean triggerCallbackIfNeeded, boolean isStarted, @AppOpsManager.AttributionFlags
+            boolean triggeredByUidStateChange, boolean isStarted, @AppOpsManager.AttributionFlags
             int attributionFlags, int attributionChainId) throws RemoteException {
-        if (triggerCallbackIfNeeded && !parent.isRunning() && isStarted) {
+        if (!triggeredByUidStateChange && !parent.isRunning() && isStarted) {
             mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                     parent.packageName, tag, true, attributionFlags, attributionChainId);
         }
@@ -263,19 +253,27 @@
      * @param clientId Id of the finishOp caller
      */
     public void finished(@NonNull IBinder clientId) {
-        finished(clientId, true);
+        finished(clientId, false);
     }
 
-    private void finished(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded) {
-        finishOrPause(clientId, triggerCallbackIfNeeded, false);
+    private void finished(@NonNull IBinder clientId, boolean triggeredByUidStateChange) {
+        finishOrPause(clientId, triggeredByUidStateChange, false);
     }
 
     /**
      * Update state when paused or finished is called. If pausing, it records the op as
      * stopping in the HistoricalRegistry, but does not delete it.
+     *
+     * @param triggeredByUidStateChange If {@code true}, then this method operates as usual, except
+     * that {@link AppOpsService#mActiveWatchers} will not be notified. This is currently only
+     * used in {@link #onUidStateChanged(int)}, for the purpose of restarting (i.e.,
+     * finishing then immediately starting again in the new uid state) the AttributedOp. In this
+     * case, the caller is responsible for guaranteeing that either the AttributedOp is started
+     * again or all {@link AppOpsService#mActiveWatchers} are notified that the AttributedOp is
+     * finished.
      */
     @SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
-    private void finishOrPause(@NonNull IBinder clientId, boolean triggerCallbackIfNeeded,
+    private void finishOrPause(@NonNull IBinder clientId, boolean triggeredByUidStateChange,
             boolean isPausing) {
         int indexOfToken = isRunning() ? mInProgressEvents.indexOfKey(clientId) : -1;
         if (indexOfToken < 0) {
@@ -320,7 +318,7 @@
                     mInProgressEvents = null;
 
                     // TODO ntmyren: Also callback for single attribution tag activity changes
-                    if (triggerCallbackIfNeeded && !parent.isRunning()) {
+                    if (!triggeredByUidStateChange && !parent.isRunning()) {
                         mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op,
                                 parent.uid, parent.packageName, tag, false,
                                 event.getAttributionFlags(), event.getAttributionChainId());
@@ -368,7 +366,7 @@
             @AppOpsManager.AttributionFlags
                     int attributionFlags, int attributionChainId) throws RemoteException {
         startedOrPaused(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
-                uidState, flags, true, false, attributionFlags, attributionChainId);
+                uidState, flags, false, false, attributionFlags, attributionChainId);
     }
 
     /**
@@ -386,7 +384,7 @@
         for (int i = 0; i < mInProgressEvents.size(); i++) {
             InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
             mPausedInProgressEvents.put(event.getClientId(), event);
-            finishOrPause(event.getClientId(), true, true);
+            finishOrPause(event.getClientId(), false, true);
 
             mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                     parent.packageName, tag, false,
@@ -475,6 +473,8 @@
             InProgressStartOpEvent event = events.get(binders.get(i));
 
             if (event != null && event.getUidState() != newState) {
+                int eventAttributionFlags = event.getAttributionFlags();
+                int eventAttributionChainId = event.getAttributionChainId();
                 try {
                     // Remove all but one unfinished start count and then call finished() to
                     // remove start event object
@@ -482,18 +482,18 @@
                     event.mNumUnfinishedStarts = 1;
                     AppOpsManager.OpEventProxyInfo proxy = event.getProxy();
 
-                    finished(event.getClientId(), false);
+                    finished(event.getClientId(), true);
 
                     // Call started() to add a new start event object and then add the
                     // previously removed unfinished start counts back
                     if (proxy != null) {
                         startedOrPaused(event.getClientId(), proxy.getUid(),
                                 proxy.getPackageName(), proxy.getAttributionTag(), newState,
-                                event.getFlags(), false, isRunning,
+                                event.getFlags(), true, isRunning,
                                 event.getAttributionFlags(), event.getAttributionChainId());
                     } else {
                         startedOrPaused(event.getClientId(), Process.INVALID_UID, null, null,
-                                newState, event.getFlags(), false, isRunning,
+                                newState, event.getFlags(), true, isRunning,
                                 event.getAttributionFlags(), event.getAttributionChainId());
                     }
 
@@ -507,6 +507,9 @@
                         Slog.e(AppOpsService.TAG,
                                 "Cannot switch to new uidState " + newState);
                     }
+                    mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op,
+                            parent.uid, parent.packageName, tag, false,
+                            eventAttributionFlags, eventAttributionChainId);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index bd9d057..6f3526f 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -37,7 +37,6 @@
 import android.content.ContentResolver;
 import android.database.ContentObserver;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
@@ -46,7 +45,6 @@
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.UserHandle;
-import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.LongSparseArray;
@@ -136,7 +134,6 @@
 
     private static final String PARAMETER_DELIMITER = ",";
     private static final String PARAMETER_ASSIGNMENT = "=";
-    private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
 
     private volatile @NonNull DiscreteRegistry mDiscreteRegistry;
 
@@ -304,10 +301,6 @@
     void dump(String prefix, PrintWriter pw, int filterUid, @Nullable String filterPackage,
             @Nullable String filterAttributionTag, int filterOp,
             @HistoricalOpsRequestFilter int filter) {
-        if (!isApiEnabled()) {
-            return;
-        }
-
         synchronized (mOnDiskLock) {
             synchronized (mInMemoryLock) {
                 pw.println();
@@ -371,11 +364,6 @@
             @OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
             long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
             String[] attributionExemptedPackages, @NonNull RemoteCallback callback) {
-        if (!isApiEnabled()) {
-            callback.sendResult(new Bundle());
-            return;
-        }
-
         final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
 
         if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
@@ -409,11 +397,6 @@
             @HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
             @OpFlags int flags, @Nullable String[] attributionExemptPkgs,
             @NonNull RemoteCallback callback) {
-        if (!isApiEnabled()) {
-            callback.sendResult(new Bundle());
-            return;
-        }
-
         final long currentTimeMillis = System.currentTimeMillis();
         if (endTimeMillis == Long.MAX_VALUE) {
             endTimeMillis = currentTimeMillis;
@@ -807,12 +790,6 @@
         }
     }
 
-    private static boolean isApiEnabled() {
-        return Binder.getCallingUid() == Process.myUid()
-                || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
-                PROPERTY_PERMISSIONS_HUB_ENABLED, true);
-    }
-
     private static final class Persistence {
         private static final boolean DEBUG = false;
 
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 68062b5..65f6af7 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -4,7 +4,7 @@
             "name": "CtsAppOpsTestCases",
             "options": [
                 {
-                  "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                  "exclude-annotation": "androidx.test.filters.FlakyTest"
                 }
             ]
         },
@@ -31,7 +31,7 @@
             "name": "CtsPermissionTestCases",
             "options": [
                 {
-                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
                 },
                 {
                     "include-filter": "android.permission.cts.BackgroundPermissionsTest"
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 6d42da6..c05a1f6 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -772,7 +772,6 @@
         final int mVolume;
         final boolean mIsLeOutput;
         final @NonNull String mEventSource;
-        final @AudioSystem.AudioFormatNativeEnumForBtCodec int mCodec;
         final int mAudioSystemDevice;
         final int mMusicDevice;
 
@@ -787,7 +786,6 @@
             mEventSource = d.mEventSource;
             mAudioSystemDevice = audioDevice;
             mMusicDevice = AudioSystem.DEVICE_NONE;
-            mCodec = codec;
         }
 
         // constructor used by AudioDeviceBroker to search similar message
@@ -796,7 +794,6 @@
             mProfile = profile;
             mEventSource = "";
             mMusicDevice = AudioSystem.DEVICE_NONE;
-            mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
             mAudioSystemDevice = 0;
             mState = 0;
             mSupprNoisy = false;
@@ -811,7 +808,6 @@
             mProfile = profile;
             mEventSource = "";
             mMusicDevice = musicDevice;
-            mCodec = AudioSystem.AUDIO_FORMAT_DEFAULT;
             mAudioSystemDevice = audioSystemDevice;
             mState = state;
             mSupprNoisy = false;
@@ -829,7 +825,6 @@
             mEventSource = src.mEventSource;
             mAudioSystemDevice = src.mAudioSystemDevice;
             mMusicDevice = src.mMusicDevice;
-            mCodec = src.mCodec;
         }
 
         // redefine equality op so we can match messages intended for this device
@@ -847,6 +842,19 @@
             }
             return false;
         }
+
+        @Override
+        public String toString() {
+            return "BtDeviceInfo: device=" + mDevice.toString()
+                            + " state=" + mState
+                            + " prof=" + mProfile
+                            + " supprNoisy=" + mSupprNoisy
+                            + " volume=" + mVolume
+                            + " isLeOutput=" + mIsLeOutput
+                            + " eventSource=" + mEventSource
+                            + " audioSystemDevice=" + mAudioSystemDevice
+                            + " musicDevice=" + mMusicDevice;
+        }
     }
 
     BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device,
@@ -859,9 +867,6 @@
                 break;
             case BluetoothProfile.A2DP:
                 audioDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
-                synchronized (mDeviceStateLock) {
-                    codec = mBtHelper.getA2dpCodec(device);
-                }
                 break;
             case BluetoothProfile.HEARING_AID:
                 audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID;
@@ -1696,8 +1701,11 @@
                 case MSG_L_SET_BT_ACTIVE_DEVICE:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
-                            mDeviceInventory.onSetBtActiveDevice(btInfo,
+                            final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
+                            @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
+                                    mBtHelper.getA2dpCodecWithFallbackToSBC(
+                                            btInfo.mDevice, "MSG_L_SET_BT_ACTIVE_DEVICE");
+                            mDeviceInventory.onSetBtActiveDevice(btInfo, codec,
                                     (btInfo.mProfile
                                             != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
                                             ? mAudioService.getBluetoothContextualVolumeStream()
@@ -1730,12 +1738,16 @@
                                 (String) msg.obj, msg.arg1);
                     }
                     break;
-                case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE:
+                case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: {
+                    final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
                     synchronized (mDeviceStateLock) {
+                        @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec =
+                                mBtHelper.getA2dpCodecWithFallbackToSBC(
+                                        btInfo.mDevice, "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE");
                         mDeviceInventory.onBluetoothDeviceConfigChange(
-                                (BtDeviceInfo) msg.obj, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
+                                btInfo, codec, BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
                     }
-                    break;
+                } break;
                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
                     onSendBecomingNoisyIntent();
                     break;
@@ -1831,20 +1843,12 @@
                     }
                     break;
                 case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: {
-                    final BtDeviceInfo info = (BtDeviceInfo) msg.obj;
-                    if (info.mDevice == null) break;
+                    final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
+                    if (btInfo.mDevice == null) break;
                     AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
-                            "msg: onBluetoothActiveDeviceChange "
-                                    + " state=" + info.mState
-                                    // only querying address as this is the only readily available
-                                    // field on the device
-                                    + " addr=" + info.mDevice.getAddress()
-                                    + " prof=" + info.mProfile
-                                    + " supprNoisy=" + info.mSupprNoisy
-                                    + " src=" + info.mEventSource
-                                    )).printLog(TAG));
+                            "msg: onBluetoothActiveDeviceChange " + btInfo)).printLog(TAG));
                     synchronized (mDeviceStateLock) {
-                        mDeviceInventory.setBluetoothActiveDevice(info);
+                        mDeviceInventory.setBluetoothActiveDevice(btInfo);
                     }
                 } break;
                 case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index da89502..60af280 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -503,9 +503,11 @@
         }
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
-    void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int streamType) {
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
+    void onSetBtActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo btInfo,
+                             @AudioSystem.AudioFormatNativeEnumForBtCodec int codec,
+                             int streamType) {
         if (AudioService.DEBUG_DEVICES) {
             Log.d(TAG, "onSetBtActiveDevice"
                     + " btDevice=" + btInfo.mDevice
@@ -518,10 +520,7 @@
         }
 
         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent("BT connected:"
-                        + " addr=" + address
-                        + " profile=" + btInfo.mProfile
-                        + " state=" + btInfo.mState
-                        + " codec=" + AudioSystem.audioFormatToString(btInfo.mCodec)));
+                        + btInfo + " codec=" + AudioSystem.audioFormatToString(codec)));
 
         new MediaMetrics.Item(mMetricsId + "onSetBtActiveDevice")
                 .set(MediaMetrics.Property.STATUS, btInfo.mProfile)
@@ -529,7 +528,7 @@
                         AudioSystem.getDeviceName(btInfo.mAudioSystemDevice))
                 .set(MediaMetrics.Property.ADDRESS, address)
                 .set(MediaMetrics.Property.ENCODING,
-                        AudioSystem.audioFormatToString(btInfo.mCodec))
+                        AudioSystem.audioFormatToString(codec))
                 .set(MediaMetrics.Property.EVENT, "onSetBtActiveDevice")
                 .set(MediaMetrics.Property.STREAM_TYPE,
                         AudioSystem.streamToString(streamType))
@@ -568,7 +567,7 @@
                                     btInfo.mVolume * 10, btInfo.mAudioSystemDevice,
                                     "onSetBtActiveDevice");
                         }
-                        makeA2dpDeviceAvailable(btInfo, "onSetBtActiveDevice");
+                        makeA2dpDeviceAvailable(btInfo, codec, "onSetBtActiveDevice");
                     }
                     break;
                 case BluetoothProfile.HEARING_AID:
@@ -594,9 +593,10 @@
     }
 
 
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ void onBluetoothDeviceConfigChange(
-            @NonNull AudioDeviceBroker.BtDeviceInfo btInfo, int event) {
+            @NonNull AudioDeviceBroker.BtDeviceInfo btInfo,
+            @AudioSystem.AudioFormatNativeEnumForBtCodec int codec, int event) {
         MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
                 + "onBluetoothDeviceConfigChange")
                 .set(MediaMetrics.Property.EVENT, BtHelper.deviceEventToString(event));
@@ -610,7 +610,6 @@
             Log.d(TAG, "onBluetoothDeviceConfigChange btDevice=" + btDevice);
         }
         int volume = btInfo.mVolume;
-        @AudioSystem.AudioFormatNativeEnumForBtCodec final int audioCodec = btInfo.mCodec;
 
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
@@ -639,8 +638,7 @@
             }
 
             mmi.set(MediaMetrics.Property.ADDRESS, address)
-                    .set(MediaMetrics.Property.ENCODING,
-                            AudioSystem.audioFormatToString(audioCodec))
+                    .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(codec))
                     .set(MediaMetrics.Property.INDEX, volume)
                     .set(MediaMetrics.Property.NAME, di.mDeviceName);
 
@@ -648,20 +646,19 @@
             if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
                 boolean a2dpCodecChange = false;
                 if (btInfo.mProfile == BluetoothProfile.A2DP) {
-                    if (di.mDeviceCodecFormat != audioCodec) {
-                        di.mDeviceCodecFormat = audioCodec;
+                    if (di.mDeviceCodecFormat != codec) {
+                        di.mDeviceCodecFormat = codec;
                         mConnectedDevices.replace(key, di);
                         a2dpCodecChange = true;
                     }
                     final int res = mAudioSystem.handleDeviceConfigChange(
-                            btInfo.mAudioSystemDevice, address,
-                            BtHelper.getName(btDevice), audioCodec);
+                            btInfo.mAudioSystemDevice, address, BtHelper.getName(btDevice), codec);
 
                     if (res != AudioSystem.AUDIO_STATUS_OK) {
                         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                                 "APM handleDeviceConfigChange failed for A2DP device addr="
                                         + address + " codec="
-                                        + AudioSystem.audioFormatToString(audioCodec))
+                                        + AudioSystem.audioFormatToString(codec))
                                 .printLog(TAG));
 
                         // force A2DP device disconnection in case of error so that AudioService
@@ -672,7 +669,7 @@
                         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                                 "APM handleDeviceConfigChange success for A2DP device addr="
                                         + address
-                                        + " codec=" + AudioSystem.audioFormatToString(audioCodec))
+                                        + " codec=" + AudioSystem.audioFormatToString(codec))
                                 .printLog(TAG));
 
                     }
@@ -1338,7 +1335,7 @@
      * @param device the device whose connection state is queried
      * @return true if connected
      */
-    // called with AudioDeviceBroker.mDeviceStateLock lock held
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     public boolean isDeviceConnected(@NonNull AudioDeviceAttributes device) {
         final String key = DeviceInfo.makeDeviceListKey(device.getInternalType(),
                 device.getAddress());
@@ -1489,7 +1486,7 @@
         }
     }
 
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ void onBtProfileDisconnected(int profile) {
         switch (profile) {
             case BluetoothProfile.HEADSET:
@@ -1554,7 +1551,7 @@
         disconnectLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
     }
 
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     private void disconnectHeadset() {
         boolean disconnect = false;
         synchronized (mDevicesLock) {
@@ -1594,9 +1591,10 @@
         return mCurAudioRoutes;
     }
 
-    // only public for mocking/spying
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
-    @VisibleForTesting
+    /**
+     * Set a Bluetooth device to active.
+     */
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     public int setBluetoothActiveDevice(@NonNull AudioDeviceBroker.BtDeviceInfo info) {
         int delay;
         synchronized (mDevicesLock) {
@@ -1617,12 +1615,7 @@
             }
 
             if (AudioService.DEBUG_DEVICES) {
-                Log.i(TAG, "setBluetoothActiveDevice device: " + info.mDevice
-                        + " profile: " + BluetoothProfile.getProfileName(info.mProfile)
-                        + " state: " + BluetoothProfile.getConnectionStateName(info.mState)
-                        + " delay(ms): " + delay
-                        + " codec:" + Integer.toHexString(info.mCodec)
-                        + " suppressNoisyIntent: " + info.mSupprNoisy);
+                Log.i(TAG, "setBluetoothActiveDevice " + info.toString() + " delay(ms): " + delay);
             }
             mDeviceBroker.postBluetoothActiveDevice(info, delay);
             if (info.mProfile == BluetoothProfile.HEARING_AID
@@ -1658,10 +1651,10 @@
 
     @GuardedBy("mDevicesLock")
     private void makeA2dpDeviceAvailable(AudioDeviceBroker.BtDeviceInfo btInfo,
+                                         @AudioSystem.AudioFormatNativeEnumForBtCodec int codec,
                                          String eventSource) {
         final String address = btInfo.mDevice.getAddress();
         final String name = BtHelper.getName(btInfo.mDevice);
-        final int a2dpCodec = btInfo.mCodec;
 
         // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
         // audio policy manager
@@ -1671,7 +1664,7 @@
         AudioDeviceAttributes ada = new AudioDeviceAttributes(
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name);
         final int res = mAudioSystem.setDeviceConnectionState(ada,
-                AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
+                AudioSystem.DEVICE_STATE_AVAILABLE, codec);
 
         // TODO: log in MediaMetrics once distinction between connection failure and
         // double connection is made.
@@ -1694,7 +1687,7 @@
         //   time_low = 0, time_mid = 0, time_hi = 0, clock_seq = 0, node = MAC Address
         UUID sensorUuid = UuidUtils.uuidFromAudioDeviceAttributes(ada);
         final DeviceInfo di = new DeviceInfo(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
-                address, a2dpCodec, sensorUuid);
+                address, codec, sensorUuid);
         final String diKey = di.getKey();
         mConnectedDevices.put(diKey, di);
         // on a connection always overwrite the device seen by AudioPolicy, see comment above when
@@ -1910,9 +1903,9 @@
     }
 
     @GuardedBy("mDevicesLock")
-    private void makeA2dpDeviceUnavailableNow(String address, int a2dpCodec) {
+    private void makeA2dpDeviceUnavailableNow(String address, int codec) {
         MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "a2dp." + address)
-                .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(a2dpCodec))
+                .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(codec))
                 .set(MediaMetrics.Property.EVENT, "makeA2dpDeviceUnavailableNow");
 
         if (address == null) {
@@ -1939,7 +1932,7 @@
         AudioDeviceAttributes ada = new AudioDeviceAttributes(
                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
         final int res = mAudioSystem.setDeviceConnectionState(ada,
-                AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
+                AudioSystem.DEVICE_STATE_UNAVAILABLE, codec);
 
         if (res != AudioSystem.AUDIO_STATUS_OK) {
             AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a3245f0..0aa9cc1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -140,6 +140,7 @@
 import android.media.VolumePolicy;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.AudioProductStrategy;
@@ -166,6 +167,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
+import android.os.ServiceDebugInfo;
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.SystemClock;
@@ -10860,6 +10862,7 @@
         mDeviceBroker.addOrUpdateBtAudioDeviceCategoryInInventory(deviceState);
         mDeviceBroker.persistAudioDeviceSettings();
 
+        mSpatializerHelper.refreshDevice(deviceState.getAudioDeviceAttributes());
         mSoundDoseHelper.setAudioDeviceCategory(addr, internalType,
                 btAudioDeviceCategory == AUDIO_DEVICE_CATEGORY_HEADPHONES);
     }
@@ -12048,6 +12051,49 @@
         }
     }
 
+    /**
+     * Update {@link AudioMixingRule}-s for already registered {@link AudioMix}-es.
+     *
+     * @param mixesToUpdate - array of already registered {@link AudioMix}-es to update.
+     * @param updatedMixingRules - array of {@link AudioMixingRule}-s corresponding to
+     *                           {@code mixesToUpdate} mixes. The array must be same size as
+     *                           {@code mixesToUpdate} and i-th {@link AudioMixingRule} must
+     *                           correspond to i-th {@link AudioMix} from mixesToUpdate array.
+     * @param pcb - {@link IAudioPolicyCallback} corresponding to the registered
+     *              {@link AudioPolicy} all {@link AudioMix}-es for {@code mixesToUpdate}
+     *              are part of.
+     * @return {@link AudioManager#SUCCESS} iff the mixing rules were updated successfully,
+     *     {@link AudioManager#ERROR} otherwise.
+     */
+    @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+    public int updateMixingRulesForPolicy(
+            @NonNull AudioMix[] mixesToUpdate,
+            @NonNull AudioMixingRule[] updatedMixingRules,
+            @NonNull IAudioPolicyCallback pcb) {
+        super.updateMixingRulesForPolicy_enforcePermission();
+        Objects.requireNonNull(mixesToUpdate);
+        Objects.requireNonNull(updatedMixingRules);
+        Objects.requireNonNull(pcb);
+        if (mixesToUpdate.length != updatedMixingRules.length) {
+            Log.e(TAG, "Provided list of audio mixes to update and corresponding mixing rules "
+                    + "have mismatching length (mixesToUpdate.length = " + mixesToUpdate.length
+                    + ", updatedMixingRules.length = " + updatedMixingRules.length +  ").");
+            return AudioManager.ERROR;
+        }
+        if (DEBUG_AP) {
+            Log.d(TAG, "updateMixingRules for " + pcb.asBinder() + "with mix rules: ");
+        }
+        synchronized (mAudioPolicies) {
+            final AudioPolicyProxy app =
+                    checkUpdateForPolicy(pcb, "Cannot add AudioMix in audio policy");
+            if (app == null) {
+                return AudioManager.ERROR;
+            }
+            return app.updateMixingRules(mixesToUpdate, updatedMixingRules) == AudioSystem.SUCCESS
+                    ? AudioManager.SUCCESS : AudioManager.ERROR;
+        }
+    }
+
     /** see AudioPolicy.setUidDeviceAffinity() */
     public int setUidDeviceAffinity(IAudioPolicyCallback pcb, int uid,
             @NonNull int[] deviceTypes, @NonNull String[] deviceAddresses) {
@@ -12785,6 +12831,35 @@
 
         }
 
+        @AudioSystem.AudioSystemError int updateMixingRules(
+                                        @NonNull AudioMix[] mixesToUpdate,
+                                        @NonNull AudioMixingRule[] updatedMixingRules) {
+            Objects.requireNonNull(mixesToUpdate);
+            Objects.requireNonNull(updatedMixingRules);
+
+            if (mixesToUpdate.length != updatedMixingRules.length) {
+                Log.e(TAG, "Provided list of audio mixes to update and corresponding mixing rules "
+                        + "have mismatching length (mixesToUpdate.length = " + mixesToUpdate.length
+                        + ", updatedMixingRules.length = " + updatedMixingRules.length +  ").");
+                return AudioSystem.BAD_VALUE;
+            }
+
+            synchronized (mMixes) {
+                try (SafeCloseable unused = ClearCallingIdentityContext.create()) {
+                    int ret = mAudioSystem.updateMixingRules(mixesToUpdate, updatedMixingRules);
+                    if (ret == AudioSystem.SUCCESS) {
+                        for (int i = 0; i < mixesToUpdate.length; i++) {
+                            AudioMix audioMixToUpdate = mixesToUpdate[i];
+                            AudioMixingRule audioMixingRule = updatedMixingRules[i];
+                            mMixes.stream().filter(audioMixToUpdate::equals).findAny().ifPresent(
+                                    mix -> mix.setAudioMixingRule(audioMixingRule));
+                        }
+                    }
+                    return ret;
+                }
+            }
+        }
+
         int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses) {
             final Integer Uid = new Integer(uid);
             if (mUidDeviceAffinities.remove(Uid) != null) {
@@ -13077,12 +13152,25 @@
 
     private static final String AUDIO_HAL_SERVICE_PREFIX = "android.hardware.audio";
 
-    private Set<Integer> getAudioHalPids() {
+    private void getAudioAidlHalPids(HashSet<Integer> pids) {
+        try {
+            ServiceDebugInfo[] infos = ServiceManager.getServiceDebugInfo();
+            if (infos == null) return;
+            for (ServiceDebugInfo info : infos) {
+                if (info.debugPid > 0 && info.name.startsWith(AUDIO_HAL_SERVICE_PREFIX)) {
+                    pids.add(info.debugPid);
+                }
+            }
+        } catch (RuntimeException e) {
+            // ignored, pid hashset does not change
+        }
+    }
+
+    private void getAudioHalHidlPids(HashSet<Integer> pids) {
         try {
             IServiceManager serviceManager = IServiceManager.getService();
             ArrayList<IServiceManager.InstanceDebugInfo> dump =
                     serviceManager.debugDump();
-            HashSet<Integer> pids = new HashSet<>();
             for (IServiceManager.InstanceDebugInfo info : dump) {
                 if (info.pid != IServiceManager.PidConstant.NO_PID
                         && info.interfaceName != null
@@ -13090,12 +13178,18 @@
                     pids.add(info.pid);
                 }
             }
-            return pids;
         } catch (RemoteException | RuntimeException e) {
-            return new HashSet<Integer>();
+            // ignored, pid hashset does not change
         }
     }
 
+    private Set<Integer> getAudioHalPids() {
+        HashSet<Integer> pids = new HashSet<>();
+        getAudioAidlHalPids(pids);
+        getAudioHalHidlPids(pids);
+        return pids;
+    }
+
     private void updateAudioHalPids() {
         Set<Integer> pidsSet = getAudioHalPids();
         if (pidsSet.isEmpty()) {
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index e70b649..4f46dd1 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -26,6 +26,7 @@
 import android.media.ISoundDose;
 import android.media.ISoundDoseCallback;
 import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
 import android.os.IBinder;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -601,6 +602,21 @@
     }
 
     /**
+     * Update already {@link AudioMixingRule}-s for already registered {@link AudioMix}-es.
+     *
+     * @param mixes              - array of registered {@link AudioMix}-es to update.
+     * @param updatedMixingRules - array of {@link AudioMixingRule}-s corresponding to
+     *                           {@code mixesToUpdate} mixes. The array must be same size as
+     *                           {@code mixesToUpdate} and i-th {@link AudioMixingRule} must
+     *                           correspond to i-th {@link AudioMix} from mixesToUpdate array.
+     */
+    public int updateMixingRules(@NonNull AudioMix[] mixes,
+            @NonNull AudioMixingRule[] updatedMixingRules) {
+        invalidateRoutingCache();
+        return AudioSystem.updatePolicyMixes(mixes, updatedMixingRules);
+    }
+
+    /**
      * Same as {@link AudioSystem#setUidDeviceAffinities(int, int[], String[])}
      * @param uid
      * @param types
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 1462b3c..6af409e 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -173,8 +173,8 @@
     //----------------------------------------------------------------------
     // Interface for AudioDeviceBroker
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized void onSystemReady() {
         mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR;
         resetBluetoothSco();
@@ -263,8 +263,20 @@
         return AudioSystem.bluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    /*package*/ synchronized @AudioSystem.AudioFormatNativeEnumForBtCodec
+            int getA2dpCodecWithFallbackToSBC(
+                    @NonNull BluetoothDevice device, @NonNull String source) {
+        @AudioSystem.AudioFormatNativeEnumForBtCodec int codec = getA2dpCodec(device);
+        if (codec == AudioSystem.AUDIO_FORMAT_DEFAULT) {
+            AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
+                    "getA2dpCodec DEFAULT from " + source + " fallback to SBC"));
+            return AudioSystem.AUDIO_FORMAT_SBC;
+        }
+        return codec;
+    }
+
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized void onReceiveBtEvent(Intent intent) {
         final String action = intent.getAction();
 
@@ -283,8 +295,8 @@
      * Exclusively called from AudioDeviceBroker when handling MSG_L_RECEIVED_BT_EVENT
      * as part of the serialization of the communication route selection
      */
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     private void onScoAudioStateChanged(int state) {
         boolean broadcast = false;
         int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
@@ -355,16 +367,16 @@
                 == BluetoothHeadset.STATE_AUDIO_CONNECTED;
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized boolean startBluetoothSco(int scoAudioMode,
                 @NonNull String eventSource) {
         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(eventSource));
         return requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized boolean stopBluetoothSco(@NonNull String eventSource) {
         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(eventSource));
         return requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, SCO_MODE_VIRTUAL_CALL);
@@ -435,8 +447,8 @@
         mScoConnectionState = state;
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized void resetBluetoothSco() {
         mScoAudioState = SCO_STATE_INACTIVE;
         broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
@@ -445,7 +457,8 @@
         mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
     }
 
-    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized void onBtProfileDisconnected(int profile) {
         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                 "BT profile " + BluetoothProfile.getProfileName(profile) + " disconnected"));
@@ -474,7 +487,8 @@
         }
     }
 
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package*/ synchronized void onBtProfileConnected(int profile, BluetoothProfile proxy) {
         AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
                 "BT profile " + BluetoothProfile.getProfileName(profile) + " connected to proxy "
@@ -522,8 +536,8 @@
         }
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     private void onHeadsetProfileConnected(BluetoothHeadset headset) {
         // Discard timeout message
         mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
@@ -642,8 +656,8 @@
         return btDevice == null ? "(null)" : btDevice.getAnonymizedAddress();
     }
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     /*package */ synchronized void onSetBtScoActiveDevice(BluetoothDevice btDevice) {
         Log.i(TAG, "onSetBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice)
                 + " -> " + getAnonymizedAddress(btDevice));
@@ -712,8 +726,8 @@
 
     //----------------------------------------------------------------------
 
-    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
-    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    // @GuardedBy("mDeviceBroker.mSetModeLock")
+    // @GuardedBy("AudioDeviceBroker.this.mDeviceStateLock")
     @GuardedBy("BtHelper.this")
     private boolean requestScoState(int state, int scoAudioMode) {
         checkScoAudioState();
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 9fa569a..35260ed 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.server.audio;
 
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES;
+import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN;
 import static android.media.AudioSystem.isBluetoothDevice;
 
 import android.annotation.NonNull;
@@ -682,8 +684,20 @@
             Log.i(TAG, "no spatialization device state found for Spatial Audio device:" + ada);
             return new Pair<>(false, false);
         }
+        boolean available = true;
+        if (isBluetoothDevice(deviceType)) {
+            // only checking headphones/binaural because external speakers cannot use transaural
+            // since their physical characteristics are unknown
+            if (deviceState.getAudioDeviceCategory() == AUDIO_DEVICE_CATEGORY_UNKNOWN
+                    || deviceState.getAudioDeviceCategory() == AUDIO_DEVICE_CATEGORY_HEADPHONES) {
+                available = (spatMode == SpatializationMode.SPATIALIZER_BINAURAL)
+                        && mBinauralSupported;
+            } else {
+                available = false;
+            }
+        }
         // found the matching device state.
-        return new Pair<>(deviceState.isSAEnabled(), true /* available */);
+        return new Pair<>(deviceState.isSAEnabled(), available);
     }
 
     private synchronized void addWirelessDeviceIfNew(@NonNull AudioDeviceAttributes ada) {
@@ -740,11 +754,36 @@
         }
     }
 
+    synchronized void refreshDevice(@NonNull AudioDeviceAttributes ada) {
+        final AdiDeviceState deviceState = findSACompatibleDeviceStateForAudioDeviceAttributes(ada);
+        if (isAvailableForAdiDeviceState(deviceState)) {
+            addCompatibleAudioDevice(ada, /*forceEnable=*/deviceState.isSAEnabled());
+            setHeadTrackerEnabled(deviceState.isHeadTrackerEnabled(), ada);
+        } else {
+            removeCompatibleAudioDevice(ada);
+        }
+    }
+
     synchronized boolean isAvailableForDevice(@NonNull AudioDeviceAttributes ada) {
         if (ada.getRole() != AudioDeviceAttributes.ROLE_OUTPUT) {
             return false;
         }
-        return findSACompatibleDeviceStateForAudioDeviceAttributes(ada) != null;
+
+        return isAvailableForAdiDeviceState(
+                findSACompatibleDeviceStateForAudioDeviceAttributes(ada));
+    }
+
+    private boolean isAvailableForAdiDeviceState(AdiDeviceState deviceState) {
+        if (deviceState == null) {
+            return false;
+        }
+
+        if (isBluetoothDevice(deviceState.getInternalDeviceType())
+                && deviceState.getAudioDeviceCategory() != AUDIO_DEVICE_CATEGORY_UNKNOWN
+                && deviceState.getAudioDeviceCategory() != AUDIO_DEVICE_CATEGORY_HEADPHONES) {
+            return false;
+        }
+        return true;
     }
 
     private synchronized boolean canBeSpatializedOnDevice(@NonNull AudioAttributes attributes,
diff --git a/services/core/java/com/android/server/audio/UuidUtils.java b/services/core/java/com/android/server/audio/UuidUtils.java
index 2003619..035bea3 100644
--- a/services/core/java/com/android/server/audio/UuidUtils.java
+++ b/services/core/java/com/android/server/audio/UuidUtils.java
@@ -45,26 +45,24 @@
      *  Generate a headtracking UUID from AudioDeviceAttributes
      */
     public static UUID uuidFromAudioDeviceAttributes(AudioDeviceAttributes device) {
-        switch (device.getInternalType()) {
-            case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP:
-                String address = device.getAddress().replace(":", "");
-                if (address.length() != 12) {
-                    return null;
-                }
-                address = "0x" + address;
-                long lsb = LSB_PREFIX_BT;
-                try {
-                    lsb |= Long.decode(address).longValue();
-                } catch (NumberFormatException e) {
-                    return null;
-                }
-                if (AudioService.DEBUG_DEVICES) {
-                    Slog.i(TAG, "uuidFromAudioDeviceAttributes lsb: " + Long.toHexString(lsb));
-                }
-                return new UUID(0, lsb);
-            default:
-                // Handle other device types here
-                return null;
+        if (!AudioSystem.isBluetoothA2dpOutDevice(device.getInternalType())
+                && !AudioSystem.isBluetoothLeOutDevice(device.getInternalType())) {
+            return null;
         }
+        String address = device.getAddress().replace(":", "");
+        if (address.length() != 12) {
+            return null;
+        }
+        address = "0x" + address;
+        long lsb = LSB_PREFIX_BT;
+        try {
+            lsb |= Long.decode(address).longValue();
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        if (AudioService.DEBUG_DEVICES) {
+            Slog.i(TAG, "uuidFromAudioDeviceAttributes lsb: " + Long.toHexString(lsb));
+        }
+        return new UUID(0, lsb);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStats.java b/services/core/java/com/android/server/biometrics/AuthenticationStats.java
index e109cc8..707240b 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStats.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStats.java
@@ -90,6 +90,11 @@
         mRejectedAttempts = 0;
     }
 
+    /** Update enrollment notification counter after sending a notification. */
+    public void updateNotificationCounter() {
+        mEnrollmentNotifications++;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index 3d1b162..fdf607d 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -68,8 +68,10 @@
         @Override
         public void onReceive(@NonNull Context context, @NonNull Intent intent) {
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
             if (userId != UserHandle.USER_NULL
                     && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
+                Slog.d(TAG, "Removing data for user: " + userId);
                 onUserRemoved(userId);
             }
         }
@@ -84,7 +86,9 @@
         mModality = modality;
         mBiometricNotification = biometricNotification;
 
-        context.registerReceiver(mBroadcastReceiver, new IntentFilter(Intent.ACTION_USER_REMOVED));
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+        context.registerReceiver(mBroadcastReceiver, intentFilter);
     }
 
     private void initializeUserAuthenticationStatsMap() {
@@ -94,6 +98,8 @@
                     mAuthenticationStatsPersister.getAllFrrStats(mModality)) {
                 mUserAuthenticationStatsMap.put(stats.getUserId(), stats);
             }
+            mAuthenticationStatsPersister.persistFrrThreshold(mThreshold);
+
             mPersisterInitialized = true;
         } catch (IllegalStateException e) {
             Slog.w(TAG, "Failed to initialize AuthenticationStatsPersister.", e);
@@ -121,10 +127,11 @@
 
         authenticationStats.authenticate(authenticated);
 
+        sendNotificationIfNeeded(userId);
+
         if (mPersisterInitialized) {
             persistDataIfNeeded(userId);
         }
-        sendNotificationIfNeeded(userId);
     }
 
     /** Check if a notification should be sent after a calculation cycle. */
@@ -164,8 +171,10 @@
         }
         if (hasEnrolledFace && !hasEnrolledFingerprint) {
             mBiometricNotification.sendFpEnrollNotification(mContext);
+            authenticationStats.updateNotificationCounter();
         } else if (!hasEnrolledFace && hasEnrolledFingerprint) {
             mBiometricNotification.sendFaceEnrollNotification(mContext);
+            authenticationStats.updateNotificationCounter();
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java
index 74e1410..5625bfd 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsPersister.java
@@ -52,6 +52,7 @@
     private static final String FINGERPRINT_REJECTIONS = "fingerprint_rejections";
     private static final String ENROLLMENT_NOTIFICATIONS = "enrollment_notifications";
     private static final String KEY = "frr_stats";
+    private static final String THRESHOLD_KEY = "frr_threshold";
 
     @NonNull private final SharedPreferences mSharedPreferences;
 
@@ -59,7 +60,7 @@
         // The package info in the context isn't initialized in the way it is for normal apps,
         // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
         // build the path manually below using the same policy that appears in ContextImpl.
-        final File prefsFile = new File(Environment.getDataSystemDeDirectory(), FILE_NAME);
+        final File prefsFile = new File(Environment.getDataSystemDirectory(), FILE_NAME);
         mSharedPreferences = context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
     }
 
@@ -137,16 +138,19 @@
                     iterator.remove();
                     break;
                 }
+                // Reset frrStatJson when user doesn't exist.
+                frrStatJson = null;
             }
 
-            // If there's existing frr stats in the file, we want to update the stats for the given
-            // modality and keep the stats for other modalities.
+            // Checks if this is a new user and there's no JSON for this user in the storage.
             if (frrStatJson == null) {
                 frrStatJson = new JSONObject().put(USER_ID, userId);
             }
             frrStatsSet.add(buildFrrStats(frrStatJson, totalAttempts, rejectedAttempts,
                     enrollmentNotifications, modality));
 
+            Slog.d(TAG, "frrStatsSet to persist: " + frrStatsSet);
+
             mSharedPreferences.edit().putStringSet(KEY, frrStatsSet).apply();
 
         } catch (JSONException e) {
@@ -154,6 +158,13 @@
         }
     }
 
+    /**
+     * Persist frr threshold.
+     */
+    public void persistFrrThreshold(float frrThreshold) {
+        mSharedPreferences.edit().putFloat(THRESHOLD_KEY, frrThreshold).apply();
+    }
+
     private Set<String> readFrrStats() {
         return mSharedPreferences.getStringSet(KEY, Set.of());
     }
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index 2ff695d..f1c74f0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -78,7 +78,8 @@
                 null /* options */, UserHandle.CURRENT);
 
         showNotificationHelper(context, name, title, content, pendingIntent, FACE_RE_ENROLL_CHANNEL,
-                FACE_RE_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET);
+                Notification.CATEGORY_SYSTEM, FACE_RE_ENROLL_NOTIFICATION_TAG,
+                Notification.VISIBILITY_SECRET);
     }
 
     /**
@@ -95,15 +96,14 @@
 
         final Intent intent = new Intent(FACE_ENROLL_ACTION);
         intent.setPackage(SETTINGS_PACKAGE);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
 
         final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
                 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
                 null /* options */, UserHandle.CURRENT);
 
         showNotificationHelper(context, name, title, content, pendingIntent, FACE_ENROLL_CHANNEL,
-                FACE_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_PUBLIC);
+                Notification.CATEGORY_RECOMMENDATION, FACE_ENROLL_NOTIFICATION_TAG,
+                Notification.VISIBILITY_PUBLIC);
     }
 
     /**
@@ -120,16 +120,14 @@
 
         final Intent intent = new Intent(FINGERPRINT_ENROLL_ACTION);
         intent.setPackage(SETTINGS_PACKAGE);
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
 
         final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context,
                 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE /* flags */,
                 null /* options */, UserHandle.CURRENT);
 
         showNotificationHelper(context, name, title, content, pendingIntent,
-                FINGERPRINT_ENROLL_CHANNEL, FINGERPRINT_ENROLL_NOTIFICATION_TAG,
-                Notification.VISIBILITY_PUBLIC);
+                Notification.CATEGORY_RECOMMENDATION, FINGERPRINT_ENROLL_CHANNEL,
+                FINGERPRINT_ENROLL_NOTIFICATION_TAG, Notification.VISIBILITY_PUBLIC);
     }
 
     /**
@@ -163,13 +161,13 @@
                 null /* options */, UserHandle.CURRENT);
 
         showNotificationHelper(context, name, title, content, pendingIntent,
-                FINGERPRINT_BAD_CALIBRATION_CHANNEL, BAD_CALIBRATION_NOTIFICATION_TAG,
-                Notification.VISIBILITY_SECRET);
+                Notification.CATEGORY_SYSTEM, FINGERPRINT_BAD_CALIBRATION_CHANNEL,
+                BAD_CALIBRATION_NOTIFICATION_TAG, Notification.VISIBILITY_SECRET);
     }
 
     private static void showNotificationHelper(Context context, String name, String title,
-                String content, PendingIntent pendingIntent, String channelName,
-                String notificationTag, int visibility) {
+                String content, PendingIntent pendingIntent, String category,
+                String channelName, String notificationTag, int visibility) {
         final NotificationManager notificationManager =
                 context.getSystemService(NotificationManager.class);
         final NotificationChannel channel = new NotificationChannel(channelName, name,
@@ -182,7 +180,7 @@
                 .setOnlyAlertOnce(true)
                 .setLocalOnly(true)
                 .setAutoCancel(true)
-                .setCategory(Notification.CATEGORY_SYSTEM)
+                .setCategory(category)
                 .setContentIntent(pendingIntent)
                 .setVisibility(visibility)
                 .build();
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 38c6a52..906c66d 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -144,6 +144,7 @@
     private final VirtualDeviceManagerInternal mVdmInternal;
     private final VirtualDeviceManager mVdm;
     private BroadcastReceiver mVirtualDeviceRemovedReceiver;
+    private VirtualDeviceManager.VirtualDeviceListener mVirtualDeviceListener;
     private final IUserManager mUm;
     private final PackageManager mPm;
     private final AppOpsManager mAppOps;
@@ -216,12 +217,14 @@
     @Override
     public void onStart() {
         publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
-        if (mVdmInternal != null) {
-            registerVirtualDeviceRemovedListener();
+        if (!android.companion.virtual.flags.Flags.vdmPublicApis() && mVdmInternal != null) {
+            registerVirtualDeviceBroadcastReceiver();
+        } else if (android.companion.virtual.flags.Flags.vdmPublicApis() && mVdm != null) {
+            registerVirtualDeviceListener();
         }
     }
 
-    private void registerVirtualDeviceRemovedListener() {
+    private void registerVirtualDeviceBroadcastReceiver() {
         if (mVirtualDeviceRemovedReceiver != null) {
             return;
         }
@@ -245,6 +248,23 @@
                 Context.RECEIVER_NOT_EXPORTED);
     }
 
+    private void registerVirtualDeviceListener() {
+        if (mVirtualDeviceListener != null) {
+            return;
+        }
+        mVirtualDeviceListener = new VirtualDeviceManager.VirtualDeviceListener() {
+            @Override
+            public void onVirtualDeviceClosed(int deviceId) {
+                synchronized (mLock) {
+                    for (int i = mClipboards.numMaps() - 1; i >= 0; i--) {
+                        mClipboards.delete(mClipboards.keyAt(i), deviceId);
+                    }
+                }
+            }
+        };
+        mVdm.registerVirtualDeviceListener(getContext().getMainExecutor(), mVirtualDeviceListener);
+    }
+
     @Override
     public void onUserStopped(@NonNull TargetUser user) {
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/connectivity/TEST_MAPPING b/services/core/java/com/android/server/connectivity/TEST_MAPPING
new file mode 100644
index 0000000..687d4b0
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/TEST_MAPPING
@@ -0,0 +1,30 @@
+{
+  "presubmit": [
+      {
+          "name": "FrameworksNetTests",
+          "options": [
+              {
+                  "exclude-annotation": "com.android.testutils.SkipPresubmit"
+              }
+          ],
+          "file_patterns": ["Vpn\\.java", "VpnIkeV2Utils\\.java", "VpnProfileStore\\.java"]
+      }
+  ],
+  "presubmit-large": [
+      {
+          "name": "CtsHostsideNetworkTests",
+          "options": [
+              {
+                "exclude-annotation": "androidx.test.filters.FlakyTest"
+              },
+              {
+                "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+              },
+              {
+                "exclude-annotation": "com.android.testutils.SkipPresubmit"
+              }
+          ],
+        "file_patterns": ["Vpn\\.java", "VpnIkeV2Utils\\.java", "VpnProfileStore\\.java"]
+      }
+  ]
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index cba5039..bfccd58 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -3066,7 +3066,8 @@
          * <p>This variable controls the retry delay, and is reset when the VPN pass network
          * validation.
          */
-        private int mValidationFailRetryCount = 0;
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+        int mValidationFailRetryCount = 0;
 
         /**
          * The number of attempts since the last successful connection.
@@ -3296,13 +3297,6 @@
                         }
                         agentConnect(this::onValidationStatus);
                         return; // Link properties are already sent.
-                    } else {
-                        // Underlying networks also set in agentConnect()
-                        doSetUnderlyingNetworks(networkAgent, Collections.singletonList(network));
-                        mNetworkCapabilities =
-                                new NetworkCapabilities.Builder(mNetworkCapabilities)
-                                        .setUnderlyingNetworks(Collections.singletonList(network))
-                                        .build();
                     }
 
                     lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked
@@ -3384,8 +3378,6 @@
 
                     final LinkProperties oldLp = makeLinkProperties();
 
-                    final boolean underlyingNetworkHasChanged =
-                            !Arrays.equals(mConfig.underlyingNetworks, new Network[]{network});
                     mConfig.underlyingNetworks = new Network[] {network};
                     mConfig.mtu = calculateVpnMtu();
 
@@ -3417,18 +3409,9 @@
                                     removed.getAddress(), removed.getPrefixLength());
                         }
                     } else {
-                        // Put below 3 updates into else block is because agentConnect() will do
-                        // those things, so there is no need to do the redundant work.
+                        // Put below update into else block is because agentConnect() will do
+                        // the same things, so there is no need to do the redundant work.
                         if (!newLp.equals(oldLp)) doSendLinkProperties(mNetworkAgent, newLp);
-                        if (underlyingNetworkHasChanged) {
-                            mNetworkCapabilities =
-                                    new NetworkCapabilities.Builder(mNetworkCapabilities)
-                                            .setUnderlyingNetworks(
-                                                    Collections.singletonList(network))
-                                            .build();
-                            doSetUnderlyingNetworks(mNetworkAgent,
-                                    Collections.singletonList(network));
-                        }
                     }
                 }
 
@@ -3554,10 +3537,28 @@
          */
         private void startOrMigrateIkeSession(@Nullable Network underlyingNetwork) {
             if (underlyingNetwork == null) {
+                // For null underlyingNetwork case, there will not be a NetworkAgent available so
+                // no underlying network update is necessary here. Note that updating
+                // mNetworkCapabilities here would also be reasonable, but it will be updated next
+                // time the VPN connects anyway.
                 Log.d(TAG, "There is no active network for starting an IKE session");
                 return;
             }
 
+            final List<Network> networks = Collections.singletonList(underlyingNetwork);
+            // Update network capabilities if underlying network is changed.
+            if (!networks.equals(mNetworkCapabilities.getUnderlyingNetworks())) {
+                mNetworkCapabilities =
+                        new NetworkCapabilities.Builder(mNetworkCapabilities)
+                                .setUnderlyingNetworks(networks)
+                                .build();
+                // No NetworkAgent case happens when Vpn tries to start a new VPN. The underlying
+                // network update will be done later with NetworkAgent connected event.
+                if (mNetworkAgent != null) {
+                    doSetUnderlyingNetworks(mNetworkAgent, networks);
+                }
+            }
+
             if (maybeMigrateIkeSessionAndUpdateVpnTransportInfo(underlyingNetwork)) return;
 
             startIkeSession(underlyingNetwork);
@@ -3897,6 +3898,18 @@
                 // Skip other invalid status if the scheduled recovery exists.
                 if (mScheduledHandleDataStallFuture != null) return;
 
+                // Trigger network validation on the underlying network to possibly cause system
+                // switch default network or try recover if the current default network is broken.
+                //
+                // For the same underlying network, the first validation result should clarify if
+                // it's caused by broken underlying network. So only perform underlying network
+                // re-evaluation after first validation failure to prevent extra network resource
+                // costs on sending probes.
+                if (mValidationFailRetryCount == 0) {
+                    mConnectivityManager.reportNetworkConnectivity(
+                            mActiveNetwork, false /* hasConnectivity */);
+                }
+
                 if (mValidationFailRetryCount < MAX_MOBIKE_RECOVERY_ATTEMPT) {
                     Log.d(TAG, "Validation failed");
 
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index df2a830..99a5398 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -25,6 +25,7 @@
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.BrightnessCorrection;
 import android.os.PowerManager;
+import android.util.LongArray;
 import android.util.MathUtils;
 import android.util.Pair;
 import android.util.Slog;
@@ -37,7 +38,11 @@
 import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
 
 import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 
@@ -840,6 +845,13 @@
         private final boolean mIsForIdleMode;
         private final DisplayWhiteBalanceController mDisplayWhiteBalanceController;
 
+        // Previous short-term models and the times that they were computed stored for debugging
+        // purposes
+        private List<Spline> mPreviousBrightnessSplines = new ArrayList<>();
+        private LongArray mBrightnessSplineChangeTimes = new LongArray();
+        private static final int NO_OF_PREVIOUS_CONFIGS_TO_LOG = 5;
+        private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+
         public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
                 float[] brightness, float maxGamma, boolean isForIdleMode,
                 DisplayWhiteBalanceController displayWhiteBalanceController) {
@@ -982,6 +994,13 @@
             mUserLux = lux;
             mUserBrightness = brightness;
             computeSpline();
+
+            if (mPreviousBrightnessSplines.size() == NO_OF_PREVIOUS_CONFIGS_TO_LOG) {
+                mPreviousBrightnessSplines.remove(0);
+                mBrightnessSplineChangeTimes.remove(0);
+            }
+            mPreviousBrightnessSplines.add(mBrightnessSpline);
+            mBrightnessSplineChangeTimes.add(System.currentTimeMillis());
         }
 
         @Override
@@ -1042,7 +1061,16 @@
             pw.println("  mDefaultConfig=" + mDefaultConfig);
             pw.println("  mBrightnessRangeAdjustmentApplied=" + mBrightnessRangeAdjustmentApplied);
 
-            dumpConfigDiff(pw, hbmTransition);
+            pw.println("  Previous short-term models (oldest to newest): ");
+            for (int i = 0; i < mPreviousBrightnessSplines.size(); i++) {
+                pw.println("  Computed at "
+                        + FORMAT.format(new Date(mBrightnessSplineChangeTimes.get(i))) + ": ");
+                dumpConfigDiff(pw, hbmTransition, mPreviousBrightnessSplines.get(i),
+                        /* shortTermModelOnly= */ true);
+            }
+
+            pw.println("  Difference between current config and default: ");
+            dumpConfigDiff(pw, hbmTransition, mBrightnessSpline, /* shortTermModelOnly= */ false);
         }
 
         @Override
@@ -1066,9 +1094,8 @@
          *
          * @param pw The print-writer to write to.
          */
-        private void dumpConfigDiff(PrintWriter pw, float hbmTransition) {
-            pw.println("  Difference between current config and default: ");
-
+        private void dumpConfigDiff(PrintWriter pw, float hbmTransition, Spline brightnessSpline,
+                boolean shortTermModelOnly) {
             Pair<float[], float[]> currentCurve = mConfig.getCurve();
             Spline currSpline = Spline.createSpline(currentCurve.first, currentCurve.second);
 
@@ -1107,7 +1134,7 @@
 
                 float defaultNits = defaultSpline.interpolate(lux);
                 float longTermNits = currSpline.interpolate(lux);
-                float shortTermNits = mBrightnessSpline.interpolate(lux);
+                float shortTermNits = brightnessSpline.interpolate(lux);
                 float brightness = mAdjustedNitsToBrightnessSpline.interpolate(shortTermNits);
 
                 String luxPrefix = (lux == mUserLux ? "^" : "");
@@ -1142,8 +1169,10 @@
                 // At 80 chars, start another row
                 if (sbLux.length() > 80 || (i == luxes.length - 1)) {
                     pw.println(sbLux);
-                    pw.println(sbNits);
-                    pw.println(sbLong);
+                    if (!shortTermModelOnly) {
+                        pw.println(sbNits);
+                        pw.println(sbLong);
+                    }
                     pw.println(sbShort);
                     pw.println(sbBrightness);
                     pw.println(sbPercent);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 0d6635d..2d763bc 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -407,6 +407,12 @@
         }
     }
 
+    void stop() {
+        if (mEglContext != null && mEglDisplay != null) {
+            EGL14.eglDestroyContext(mEglDisplay, mEglContext);
+        }
+    }
+
     /**
      * Draws an animation frame showing the color fade activated at the
      * specified level.
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index c0c60a4..e3dafa4 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -282,6 +282,8 @@
  *      <screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>
  *      <screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>
  *      <screenBrightnessRampSlowIncrease>0.04</screenBrightnessRampSlowIncrease>
+ *      <screenBrightnessRampSlowDecreaseIdle>0.05</screenBrightnessRampSlowDecreaseIdle>
+ *      <screenBrightnessRampSlowIncreaseIdle>0.06</screenBrightnessRampSlowIncreaseIdle>
  *
  *      <screenBrightnessRampIncreaseMaxMillis>2000</screenBrightnessRampIncreaseMaxMillis>
  *      <screenBrightnessRampDecreaseMaxMillis>3000</screenBrightnessRampDecreaseMaxMillis>
@@ -597,6 +599,8 @@
     private float mBrightnessRampFastIncrease = Float.NaN;
     private float mBrightnessRampSlowDecrease = Float.NaN;
     private float mBrightnessRampSlowIncrease = Float.NaN;
+    private float mBrightnessRampSlowDecreaseIdle = Float.NaN;
+    private float mBrightnessRampSlowIncreaseIdle = Float.NaN;
     private long mBrightnessRampDecreaseMaxMillis = 0;
     private long mBrightnessRampIncreaseMaxMillis = 0;
     private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
@@ -1039,6 +1043,14 @@
         return mBrightnessRampSlowIncrease;
     }
 
+    public float getBrightnessRampSlowDecreaseIdle() {
+        return mBrightnessRampSlowDecreaseIdle;
+    }
+
+    public float getBrightnessRampSlowIncreaseIdle() {
+        return mBrightnessRampSlowIncreaseIdle;
+    }
+
     public long getBrightnessRampDecreaseMaxMillis() {
         return mBrightnessRampDecreaseMaxMillis;
     }
@@ -1654,6 +1666,8 @@
                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
                 + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
                 + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+                + ", mBrightnessRampSlowDecreaseIdle=" + mBrightnessRampSlowDecreaseIdle
+                + ", mBrightnessRampSlowIncreaseIdle=" + mBrightnessRampSlowIncreaseIdle
                 + ", mBrightnessRampDecreaseMaxMillis=" + mBrightnessRampDecreaseMaxMillis
                 + ", mBrightnessRampIncreaseMaxMillis=" + mBrightnessRampIncreaseMaxMillis
                 + "\n"
@@ -1845,6 +1859,8 @@
         mBrightnessRampFastIncrease = PowerManager.BRIGHTNESS_MAX;
         mBrightnessRampSlowDecrease = PowerManager.BRIGHTNESS_MAX;
         mBrightnessRampSlowIncrease = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampSlowDecreaseIdle = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampSlowIncreaseIdle = PowerManager.BRIGHTNESS_MAX;
         mBrightnessRampDecreaseMaxMillis = 0;
         mBrightnessRampIncreaseMaxMillis = 0;
         setSimpleMappingStrategyValues();
@@ -2665,6 +2681,12 @@
     }
 
     private void loadBrightnessRamps(DisplayConfiguration config) {
+        // Interactive must come first, since idle falls back to it when values are unspecified.
+        loadBrightnessRampsInteractive(config);
+        loadBrightnessRampsIdle(config);
+    }
+
+    private void loadBrightnessRampsInteractive(DisplayConfiguration config) {
         // Priority 1: Value in the display device config (float)
         // Priority 2: Value in the config.xml (int)
         final BigDecimal fastDownDecimal = config.getScreenBrightnessRampFastDecrease();
@@ -2697,6 +2719,27 @@
         }
     }
 
+    private void loadBrightnessRampsIdle(DisplayConfiguration config) {
+        // Priority 1: Idle value in the display device config (float)
+        // Priority 2: Fallback - Interactive value from wherever.
+        final BigDecimal slowDownDecimalIdle = config.getScreenBrightnessRampSlowDecreaseIdle();
+        final BigDecimal slowUpDecimalIdle = config.getScreenBrightnessRampSlowIncreaseIdle();
+
+        if (slowDownDecimalIdle != null && slowUpDecimalIdle != null) {
+            mBrightnessRampSlowDecreaseIdle = slowDownDecimalIdle.floatValue();
+            mBrightnessRampSlowIncreaseIdle = slowUpDecimalIdle.floatValue();
+        } else {
+            if (slowDownDecimalIdle != null || slowUpDecimalIdle != null) {
+                Slog.w(TAG, "Per display idle brightness ramp values ignored because not all "
+                        + "values are present in display device config");
+            }
+            // If these values don't exist, fall back to interactive mode values, since
+            // there are no idle ramp values in config.xml
+            mBrightnessRampSlowDecreaseIdle = mBrightnessRampSlowDecrease;
+            mBrightnessRampSlowIncreaseIdle = mBrightnessRampSlowIncrease;
+        }
+    }
+
     private void loadBrightnessRampsFromConfigXml() {
         mBrightnessRampFastIncrease = BrightnessSynchronizer.brightnessIntToFloat(
                 mContext.getResources().getInteger(R.integer.config_brightness_ramp_rate_fast));
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b994105..90c7ce7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -146,6 +146,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.SettingsWrapper;
 import com.android.server.AnimationThread;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
@@ -159,7 +160,7 @@
 import com.android.server.display.mode.DisplayModeDirector;
 import com.android.server.display.utils.SensorUtils;
 import com.android.server.input.InputManagerInternal;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
 import com.android.server.wm.SurfaceAnimationThread;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -472,6 +473,8 @@
     private SensorManager mSensorManager;
     private BrightnessTracker mBrightnessTracker;
 
+    private SmallAreaDetectionController mSmallAreaDetectionController;
+
 
     // Whether minimal post processing is allowed by the user.
     @GuardedBy("mSyncRoot")
@@ -547,9 +550,9 @@
         mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
         mUiHandler = UiThread.getHandler();
         mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
-        mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo,
-                new LogicalDisplayListener(), mSyncRoot, mHandler,
-                new FoldSettingWrapper(mContext.getContentResolver()), mFlags);
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
+                new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo,
+                new LogicalDisplayListener(), mSyncRoot, mHandler, mFlags);
         mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
         mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
         Resources resources = mContext.getResources();
@@ -738,6 +741,8 @@
         filter.addAction(Intent.ACTION_DOCK_EVENT);
 
         mContext.registerReceiver(mIdleModeReceiver, filter);
+
+        mSmallAreaDetectionController = SmallAreaDetectionController.create(mContext);
     }
 
     @VisibleForTesting
@@ -3128,6 +3133,9 @@
         pw.println();
         mDisplayModeDirector.dump(pw);
         mBrightnessSynchronizer.dump(pw);
+        if (mSmallAreaDetectionController != null) {
+            mSmallAreaDetectionController.dump(pw);
+        }
     }
 
     private static float[] getFloatArray(TypedArray array) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 79b7343..40dbabf 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -430,6 +430,8 @@
     private float mBrightnessRampRateFastIncrease;
     private float mBrightnessRampRateSlowDecrease;
     private float mBrightnessRampRateSlowIncrease;
+    private float mBrightnessRampRateSlowDecreaseIdle;
+    private float mBrightnessRampRateSlowIncreaseIdle;
 
     // Report HBM brightness change to StatsD
     private int mDisplayStatsId;
@@ -1312,6 +1314,10 @@
         mBrightnessRampRateFastIncrease = mDisplayDeviceConfig.getBrightnessRampFastIncrease();
         mBrightnessRampRateSlowDecrease = mDisplayDeviceConfig.getBrightnessRampSlowDecrease();
         mBrightnessRampRateSlowIncrease = mDisplayDeviceConfig.getBrightnessRampSlowIncrease();
+        mBrightnessRampRateSlowDecreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowDecreaseIdle();
+        mBrightnessRampRateSlowIncreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowIncreaseIdle();
         mBrightnessRampDecreaseMaxTimeMillis =
                 mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis();
         mBrightnessRampIncreaseMaxTimeMillis =
@@ -1922,12 +1928,16 @@
                 } else {
                     boolean isIncreasing = animateValue > currentBrightness;
                     final float rampSpeed;
+                    final boolean idle = mAutomaticBrightnessController != null
+                            && mAutomaticBrightnessController.isInIdleMode();
                     if (isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowIncrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle
+                                : mBrightnessRampRateSlowIncrease;
                     } else if (isIncreasing && !slowChange) {
                         rampSpeed = mBrightnessRampRateFastIncrease;
                     } else if (!isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowDecrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowDecreaseIdle
+                                : mBrightnessRampRateSlowDecrease;
                     } else {
                         rampSpeed = mBrightnessRampRateFastDecrease;
                     }
@@ -3526,7 +3536,8 @@
 
         DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
                 int displayId, int displayState) {
-            return new DisplayPowerState(blanker, colorFade, displayId, displayState);
+            return new DisplayPowerState(blanker, colorFade, displayId, displayState,
+                    new Handler(/*async=*/ true));
         }
 
         DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 6c2240b..051c886 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -319,8 +319,6 @@
     // Must only be accessed on the handler thread.
     private DisplayPowerState mPowerState;
 
-
-
     // The currently active screen on unblocker.  This field is non-null whenever
     // we are waiting for a callback to release it and unblock the screen.
     private ScreenOnUnblocker mPendingScreenOnUnblocker;
@@ -357,6 +355,8 @@
     private float mBrightnessRampRateFastIncrease;
     private float mBrightnessRampRateSlowDecrease;
     private float mBrightnessRampRateSlowIncrease;
+    private float mBrightnessRampRateSlowDecreaseIdle;
+    private float mBrightnessRampRateSlowIncreaseIdle;
 
     // Report HBM brightness change to StatsD
     private int mDisplayStatsId;
@@ -1127,6 +1127,10 @@
         mBrightnessRampRateFastIncrease = mDisplayDeviceConfig.getBrightnessRampFastIncrease();
         mBrightnessRampRateSlowDecrease = mDisplayDeviceConfig.getBrightnessRampSlowDecrease();
         mBrightnessRampRateSlowIncrease = mDisplayDeviceConfig.getBrightnessRampSlowIncrease();
+        mBrightnessRampRateSlowDecreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowDecreaseIdle();
+        mBrightnessRampRateSlowIncreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowIncreaseIdle();
         mBrightnessRampDecreaseMaxTimeMillis =
                 mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis();
         mBrightnessRampIncreaseMaxTimeMillis =
@@ -1535,12 +1539,16 @@
                 } else {
                     boolean isIncreasing = animateValue > currentBrightness;
                     final float rampSpeed;
+                    final boolean idle = mAutomaticBrightnessController != null
+                            && mAutomaticBrightnessController.isInIdleMode();
                     if (isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowIncrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle
+                                : mBrightnessRampRateSlowIncrease;
                     } else if (isIncreasing && !slowChange) {
                         rampSpeed = mBrightnessRampRateFastIncrease;
                     } else if (!isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowDecrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowDecreaseIdle
+                                : mBrightnessRampRateSlowDecrease;
                     } else {
                         rampSpeed = mBrightnessRampRateFastDecrease;
                     }
@@ -2861,7 +2869,8 @@
 
         DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
                 int displayId, int displayState) {
-            return new DisplayPowerState(blanker, colorFade, displayId, displayState);
+            return new DisplayPowerState(blanker, colorFade, displayId, displayState,
+                    new Handler(/*async=*/ true));
         }
 
         DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 2c257a1..85c6a6d 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -74,8 +74,9 @@
     private volatile boolean mStopped;
 
     DisplayPowerState(
-            DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState) {
-        mHandler = new Handler(true /*async*/);
+            DisplayBlanker blanker, ColorFade colorFade, int displayId, int displayState,
+            Handler handler) {
+        mHandler = handler;
         mChoreographer = Choreographer.getInstance();
         mBlanker = blanker;
         mColorFade = colorFade;
@@ -317,6 +318,7 @@
         mStopped = true;
         mPhotonicModulator.interrupt();
         dismissColorFade();
+        stopColorFade();
         mCleanListener = null;
         mHandler.removeCallbacksAndMessages(null);
     }
@@ -376,6 +378,11 @@
         }
     }
 
+    // Clears up color fade resources.
+    private void stopColorFade() {
+        if (mColorFade != null) mColorFade.stop();
+    }
+
     private final Runnable mScreenUpdateRunnable = new Runnable() {
         @Override
         public void run() {
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index cbe0fc7..b3b16ad 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -43,7 +43,7 @@
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.layout.DisplayIdProducer;
 import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -149,7 +149,7 @@
     private final Listener mListener;
     private final DisplayManagerService.SyncRoot mSyncRoot;
     private final LogicalDisplayMapperHandler mHandler;
-    private final FoldSettingWrapper mFoldSettingWrapper;
+    private final FoldSettingProvider mFoldSettingProvider;
     private final PowerManager mPowerManager;
 
     /**
@@ -196,26 +196,27 @@
     private boolean mInteractive;
     private final DisplayManagerFlags mFlags;
 
-    LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+    LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+            @NonNull DisplayDeviceRepository repo,
             @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
-            @NonNull Handler handler, FoldSettingWrapper foldSettingWrapper,
-            DisplayManagerFlags flags) {
-        this(context, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap(
-                (isDefault) -> isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++),
-                foldSettingWrapper, flags);
+            @NonNull Handler handler, DisplayManagerFlags flags) {
+        this(context, foldSettingProvider, repo, listener, syncRoot, handler,
+                new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
+                        : sNextNonDefaultDisplayId++), flags);
     }
 
-    LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+    LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+            @NonNull DisplayDeviceRepository repo,
             @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
             @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap,
-            FoldSettingWrapper foldSettingWrapper, DisplayManagerFlags flags) {
+            DisplayManagerFlags flags) {
         mSyncRoot = syncRoot;
         mPowerManager = context.getSystemService(PowerManager.class);
         mInteractive = mPowerManager.isInteractive();
         mHandler = new LogicalDisplayMapperHandler(handler.getLooper());
         mDisplayDeviceRepo = repo;
         mListener = listener;
-        mFoldSettingWrapper = foldSettingWrapper;
+        mFoldSettingProvider = foldSettingProvider;
         mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
         mSupportsConcurrentInternalDisplays = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_supportsConcurrentInternalDisplays);
@@ -488,10 +489,13 @@
                 });
             } else if (sleepDevice) {
                 // Send the device to sleep when required.
+                int goToSleepFlag =
+                        mFoldSettingProvider.shouldSleepOnFold() ? 0
+                                : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP;
                 mHandler.post(() -> {
                     mPowerManager.goToSleep(SystemClock.uptimeMillis(),
                             PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD,
-                            PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+                            goToSleepFlag);
                 });
             }
         }
@@ -565,7 +569,8 @@
                 && mDeviceStatesOnWhichToSleep.get(pendingState)
                 && !mDeviceStatesOnWhichToSleep.get(currentState)
                 && !isOverrideActive
-                && isInteractive && isBootCompleted && !mFoldSettingWrapper.shouldStayAwakeOnFold();
+                && isInteractive && isBootCompleted
+                && !mFoldSettingProvider.shouldStayAwakeOnFold();
     }
 
     private boolean areAllTransitioningDisplaysOffLocked() {
diff --git a/services/core/java/com/android/server/display/SmallAreaDetectionController.java b/services/core/java/com/android/server/display/SmallAreaDetectionController.java
new file mode 100644
index 0000000..adaa539
--- /dev/null
+++ b/services/core/java/com/android/server/display/SmallAreaDetectionController.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Map;
+
+final class SmallAreaDetectionController {
+    private static native void nativeUpdateSmallAreaDetection(int[] uids, float[] thresholds);
+    private static native void nativeSetSmallAreaDetectionThreshold(int uid, float threshold);
+
+    // TODO(b/281720315): Move this to DeviceConfig once server side ready.
+    private static final String KEY_SMALL_AREA_DETECTION_ALLOWLIST =
+            "small_area_detection_allowlist";
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final PackageManagerInternal mPackageManager;
+    private final UserManagerInternal mUserManager;
+    @GuardedBy("mLock")
+    private final Map<String, Float> mAllowPkgMap = new ArrayMap<>();
+    // TODO(b/298722189): Update allowlist when user changes
+    @GuardedBy("mLock")
+    private int[] mUserIds;
+
+    static SmallAreaDetectionController create(@NonNull Context context) {
+        final SmallAreaDetectionController controller =
+                new SmallAreaDetectionController(context, DeviceConfigInterface.REAL);
+        final String property = DeviceConfigInterface.REAL.getProperty(
+                DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_SMALL_AREA_DETECTION_ALLOWLIST);
+        controller.updateAllowlist(property);
+        return controller;
+    }
+
+    @VisibleForTesting
+    SmallAreaDetectionController(Context context, DeviceConfigInterface deviceConfig) {
+        mContext = context;
+        mPackageManager = LocalServices.getService(PackageManagerInternal.class);
+        mUserManager = LocalServices.getService(UserManagerInternal.class);
+        deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+                BackgroundThread.getExecutor(),
+                new SmallAreaDetectionController.OnPropertiesChangedListener());
+        mPackageManager.getPackageList(new PackageReceiver());
+    }
+
+    @VisibleForTesting
+    void updateAllowlist(@Nullable String property) {
+        synchronized (mLock) {
+            mAllowPkgMap.clear();
+            if (property != null) {
+                final String[] mapStrings = property.split(",");
+                for (String mapString : mapStrings) putToAllowlist(mapString);
+            } else {
+                final String[] defaultMapStrings = mContext.getResources()
+                        .getStringArray(R.array.config_smallAreaDetectionAllowlist);
+                for (String defaultMapString : defaultMapStrings) putToAllowlist(defaultMapString);
+            }
+            updateSmallAreaDetection();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void putToAllowlist(String rowData) {
+        // Data format: package:threshold - e.g. "com.abc.music:0.05"
+        final String[] items = rowData.split(":");
+        if (items.length == 2) {
+            try {
+                final String pkg = items[0];
+                final float threshold = Float.valueOf(items[1]);
+                mAllowPkgMap.put(pkg, threshold);
+            } catch (Exception e) {
+                // Just skip if items[1] - the threshold is not parsable number
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void updateUidListForAllUsers(SparseArray<Float> list, String pkg, float threshold) {
+        for (int i = 0; i < mUserIds.length; i++) {
+            final int userId = mUserIds[i];
+            final int uid = mPackageManager.getPackageUid(pkg, 0, userId);
+            if (uid > 0) list.put(uid, threshold);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void updateSmallAreaDetection() {
+        if (mAllowPkgMap.isEmpty()) return;
+
+        mUserIds = mUserManager.getUserIds();
+
+        final SparseArray<Float> uidThresholdList = new SparseArray<>();
+        for (String pkg : mAllowPkgMap.keySet()) {
+            final float threshold = mAllowPkgMap.get(pkg);
+            updateUidListForAllUsers(uidThresholdList, pkg, threshold);
+        }
+
+        final int[] uids = new int[uidThresholdList.size()];
+        final float[] thresholds = new float[uidThresholdList.size()];
+        for (int i = 0; i < uidThresholdList.size();  i++) {
+            uids[i] = uidThresholdList.keyAt(i);
+            thresholds[i] = uidThresholdList.valueAt(i);
+        }
+        updateSmallAreaDetection(uids, thresholds);
+    }
+
+    @VisibleForTesting
+    void updateSmallAreaDetection(int[] uids, float[] thresholds) {
+        nativeUpdateSmallAreaDetection(uids, thresholds);
+    }
+
+    void setSmallAreaDetectionThreshold(int uid, float threshold) {
+        nativeSetSmallAreaDetectionThreshold(uid, threshold);
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("Small area detection allowlist");
+        pw.println("  Packages:");
+        synchronized (mLock) {
+            for (String pkg : mAllowPkgMap.keySet()) {
+                pw.println("    " + pkg + " threshold = " + mAllowPkgMap.get(pkg));
+            }
+            pw.println("  mUserIds=" + Arrays.toString(mUserIds));
+        }
+    }
+
+    private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
+        public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+            if (properties.getKeyset().contains(KEY_SMALL_AREA_DETECTION_ALLOWLIST)) {
+                updateAllowlist(
+                        properties.getString(KEY_SMALL_AREA_DETECTION_ALLOWLIST, null /*default*/));
+            }
+        }
+    }
+
+    private final class PackageReceiver implements PackageManagerInternal.PackageListObserver {
+        @Override
+        public void onPackageAdded(@NonNull String packageName, int uid) {
+            synchronized (mLock) {
+                if (mAllowPkgMap.containsKey(packageName)) {
+                    setSmallAreaDetectionThreshold(uid, mAllowPkgMap.get(packageName));
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index f6d06aa..955b8d9 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -1062,8 +1062,10 @@
     }
 
     private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
+        WifiP2pWfdInfo wfdInfo = device.getWfdInfo();
+        boolean isSessionAvailable = wfdInfo != null && wfdInfo.isSessionAvailable();
         return new WifiDisplay(device.deviceAddress, device.deviceName, null,
-                true, device.getWfdInfo().isSessionAvailable(), false);
+                true, isSessionAvailable, false);
     }
 
     private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1ec8b10..131eec3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -116,6 +116,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
+import android.view.IWindowManager;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -123,6 +124,7 @@
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ImeTracker;
 import android.view.inputmethod.InputBinding;
@@ -2988,7 +2990,8 @@
                     "Waiting for the lazy init of mImeDrawsImeNavBarRes");
         }
         final boolean canImeDrawsImeNavBar =
-                mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get();
+                mImeDrawsImeNavBarRes != null && mImeDrawsImeNavBarRes.get()
+                        && hasNavigationBarOnCurrentDisplay();
         final boolean shouldShowImeSwitcherWhenImeIsShown = shouldShowImeSwitcherLocked(
                 InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE);
         return (canImeDrawsImeNavBar ? InputMethodNavButtonFlags.IME_DRAWS_IME_NAV_BAR : 0)
@@ -2996,6 +2999,21 @@
                 ? InputMethodNavButtonFlags.SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0);
     }
 
+    /**
+     * Whether the current display has a navigation bar. When this is {@code false} (e.g. emulator),
+     * the IME should <em>not</em> draw the IME navigation bar.
+     */
+    @GuardedBy("ImfLock.class")
+    private boolean hasNavigationBarOnCurrentDisplay() {
+        final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+        try {
+            return wm.hasNavigationBar(mCurTokenDisplayId != INVALID_DISPLAY
+                    ? mCurTokenDisplayId : DEFAULT_DISPLAY);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @GuardedBy("ImfLock.class")
     private boolean shouldShowImeSwitcherLocked(int visibility) {
         if (!mShowOngoingImeSwitcherForPhones) return false;
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index 39b8bfd..36adea7 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -73,6 +73,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.HexDump;
+import com.android.modules.utils.build.SdkLevel;
 import com.android.net.module.util.NetdUtils;
 import com.android.net.module.util.NetdUtils.ModifyOperation;
 import com.android.net.module.util.PermissionUtils;
@@ -782,7 +783,10 @@
     @Override
     public boolean getIpForwardingEnabled() throws IllegalStateException{
         PermissionUtils.enforceNetworkStackPermission(mContext);
-
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException(
+                    "NMS#getIpForwardingEnabled not supported in V+");
+        }
         try {
             return mNetdService.ipfwdEnabled();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -793,7 +797,10 @@
     @Override
     public void setIpForwardingEnabled(boolean enable) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
-        try {
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException(
+                    "NMS#setIpForwardingEnabled not supported in V+");
+        }        try {
             if (enable) {
                 mNetdService.ipfwdEnableForwarding("tethering");
             } else {
@@ -807,6 +814,9 @@
     @Override
     public void startTethering(String[] dhcpRange) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#startTethering not supported in V+");
+        }
         try {
             NetdUtils.tetherStart(mNetdService, true /* usingLegacyDnsProxy */, dhcpRange);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -817,6 +827,9 @@
     @Override
     public void stopTethering() {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#stopTethering not supported in V+");
+        }
         try {
             mNetdService.tetherStop();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -827,6 +840,9 @@
     @Override
     public boolean isTetheringStarted() {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#isTetheringStarted not supported in V+");
+        }
         try {
             return mNetdService.tetherIsEnabled();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -837,6 +853,9 @@
     @Override
     public void tetherInterface(String iface) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#tetherInterface not supported in V+");
+        }
         try {
             final LinkAddress addr = getInterfaceConfig(iface).getLinkAddress();
             final IpPrefix dest = new IpPrefix(addr.getAddress(), addr.getPrefixLength());
@@ -849,6 +868,9 @@
     @Override
     public void untetherInterface(String iface) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#untetherInterface not supported in V+");
+        }
         try {
             NetdUtils.untetherInterface(mNetdService, iface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -859,6 +881,10 @@
     @Override
     public String[] listTetheredInterfaces() {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException(
+                    "NMS#listTetheredInterfaces not supported in V+");
+        }
         try {
             return mNetdService.tetherInterfaceList();
         } catch (RemoteException | ServiceSpecificException e) {
@@ -869,6 +895,9 @@
     @Override
     public void enableNat(String internalInterface, String externalInterface) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#enableNat not supported in V+");
+        }
         try {
             mNetdService.tetherAddForward(internalInterface, externalInterface);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -879,6 +908,9 @@
     @Override
     public void disableNat(String internalInterface, String externalInterface) {
         PermissionUtils.enforceNetworkStackPermission(mContext);
+        if (SdkLevel.isAtLeastV()) {
+            throw new UnsupportedOperationException("NMS#disableNat not supported in V+");
+        }
         try {
             mNetdService.tetherRemoveForward(internalInterface, externalInterface);
         } catch (RemoteException | ServiceSpecificException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6f0a4b4..69b9e25 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -118,7 +118,6 @@
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
-import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.WAKE_LOCK_FOR_POSTING_NOTIFICATION;
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -533,6 +532,8 @@
     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S_V2)
     private static final long NOTIFICATION_LOG_ASSISTANT_CANCEL = 195579280L;
 
+    private static final Duration POST_WAKE_LOCK_TIMEOUT = Duration.ofSeconds(30);
+
     private IActivityManager mAm;
     private ActivityTaskManagerInternal mAtm;
     private ActivityManager mActivityManager;
@@ -2328,8 +2329,7 @@
         mRankingHandler = rankingHandler;
         mConditionProviders = conditionProviders;
         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders,
-                new SysUiStatsEvent.BuilderFactory(), flagResolver,
-                new ZenModeEventLogger(mPackageManagerClient));
+                flagResolver, new ZenModeEventLogger(mPackageManagerClient));
         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
             @Override
             public void onConfigChanged() {
@@ -2390,7 +2390,6 @@
                 mNotificationChannelLogger,
                 mAppOps,
                 mUserProfiles,
-                new SysUiStatsEvent.BuilderFactory(),
                 mShowReviewPermissionsNotification);
         mRankingHelper = new RankingHelper(getContext(),
                 mRankingHandler,
@@ -2678,7 +2677,7 @@
         mStatsManager.setPullAtomCallback(
                 DND_MODE_RULE,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                ConcurrentUtils.DIRECT_EXECUTOR,
                 mPullAtomCallback
         );
     }
@@ -6678,22 +6677,14 @@
     }
 
     private PostNotificationTracker acquireWakeLockForPost(String pkg, int uid) {
-        if (mFlagResolver.isEnabled(WAKE_LOCK_FOR_POSTING_NOTIFICATION)
-                && Binder.withCleanCallingIdentity(
-                    () -> DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                        SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, false))) {
-            // The package probably doesn't have WAKE_LOCK permission and should not require it.
-            return Binder.withCleanCallingIdentity(() -> {
-                WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                        "NotificationManagerService:post:" + pkg);
-                wakeLock.setWorkSource(new WorkSource(uid, pkg));
-                // TODO(b/275044361): Adjust to a more reasonable number when we have the data.
-                wakeLock.acquire(30_000);
-                return mPostNotificationTrackerFactory.newTracker(wakeLock);
-            });
-        } else {
-            return mPostNotificationTrackerFactory.newTracker(null);
-        }
+        // The package probably doesn't have WAKE_LOCK permission and should not require it.
+        return Binder.withCleanCallingIdentity(() -> {
+            WakeLock wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    "NotificationManagerService:post:" + pkg);
+            wakeLock.setWorkSource(new WorkSource(uid, pkg));
+            wakeLock.acquire(POST_WAKE_LOCK_TIMEOUT.toMillis());
+            return mPostNotificationTrackerFactory.newTracker(wakeLock);
+        });
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 0e37f10..b132a23 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -25,7 +25,6 @@
 import static android.app.NotificationManager.IMPORTANCE_MAX;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
@@ -78,6 +77,7 @@
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
@@ -169,7 +169,6 @@
      * fields.
      */
     private static final int DEFAULT_LOCKED_APP_FIELDS = 0;
-    private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
 
     /**
      * All user-lockable fields for a given application.
@@ -208,7 +207,6 @@
             ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager,
             NotificationChannelLogger notificationChannelLogger,
             AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles,
-            SysUiStatsEvent.BuilderFactory statsEventBuilderFactory,
             boolean showReviewPermissionsNotification) {
         mContext = context;
         mZenModeHelper = zenHelper;
@@ -219,7 +217,6 @@
         mNotificationChannelLogger = notificationChannelLogger;
         mAppOps = appOpsManager;
         mUserProfiles = userProfiles;
-        mStatsEventBuilderFactory = statsEventBuilderFactory;
         mShowReviewPermissionsNotification = showReviewPermissionsNotification;
 
         XML_VERSION = 4;
@@ -2190,11 +2187,7 @@
                     break;
                 }
                 pulledEvents++;
-                SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
-                        .setAtomId(PACKAGE_NOTIFICATION_PREFERENCES);
                 final PackagePreferences r = mPackagePreferences.valueAt(i);
-                event.writeInt(r.uid);
-                event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
 
                 // collect whether this package's importance info was user-set for later, if needed
                 // before the migration is enabled, this will simply default to false in all cases.
@@ -2214,15 +2207,7 @@
 
                     pkgsWithPermissionsToHandle.remove(key);
                 }
-                event.writeInt(importance);
 
-                event.writeInt(r.visibility);
-                event.writeInt(r.lockedAppFields);
-
-                // optional bool user_set_importance = 5;
-                event.writeBoolean(importanceIsUserSet);
-
-                // optional FsiState fsi_state = 6;
                 final boolean isStickyHunFlagEnabled = SystemUiSystemPropertiesFlags.getResolver()
                         .isEnabled(NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI);
 
@@ -2232,20 +2217,23 @@
                 final int fsiState = getFsiState(r.pkg, r.uid, requestedFSIPermission,
                         isStickyHunFlagEnabled);
 
-                event.writeInt(fsiState);
-
-                // optional bool is_fsi_permission_user_set = 7;
                 final int currentPermissionFlags = mPm.getPermissionFlags(
                         android.Manifest.permission.USE_FULL_SCREEN_INTENT, r.pkg,
                         UserHandle.getUserHandleForUid(r.uid));
 
-                final boolean isUserSet =
+                final boolean fsiIsUserSet =
                         isFsiPermissionUserSet(r.pkg, r.uid, fsiState, currentPermissionFlags,
                                 isStickyHunFlagEnabled);
 
-                event.writeBoolean(isUserSet);
-
-                events.add(event.build());
+                events.add(FrameworkStatsLog.buildStatsEvent(
+                        PACKAGE_NOTIFICATION_PREFERENCES,
+                        /* optional int32 uid = 1 [(is_uid) = true] */ r.uid,
+                        /* optional int32 importance = 2 */ importance,
+                        /* optional int32 visibility = 3 */ r.visibility,
+                        /* optional int32 user_locked_fields = 4 */ r.lockedAppFields,
+                        /* optional bool user_set_importance = 5 */ importanceIsUserSet,
+                        /* optional FsiState fsi_state = 6 */ fsiState,
+                        /* optional bool is_fsi_permission_user_set = 7 */ fsiIsUserSet));
             }
         }
 
@@ -2256,18 +2244,18 @@
                     break;
                 }
                 pulledEvents++;
-                SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
-                        .setAtomId(PACKAGE_NOTIFICATION_PREFERENCES);
-                event.writeInt(p.first);
-                event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
-                event.writeInt(pkgPermissions.get(p).first ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
-
-                // fill out the rest of the fields with default values so as not to confuse the
-                // builder
-                event.writeInt(DEFAULT_VISIBILITY);
-                event.writeInt(DEFAULT_LOCKED_APP_FIELDS);
-                event.writeBoolean(pkgPermissions.get(p).second); // user_set_importance field
-                events.add(event.build());
+                // Because all fields are required in FrameworkStatsLog.buildStatsEvent, we have
+                // to fill in default values for all the unspecified fields.
+                events.add(FrameworkStatsLog.buildStatsEvent(
+                        PACKAGE_NOTIFICATION_PREFERENCES,
+                        /* optional int32 uid = 1 [(is_uid) = true] */ p.first,
+                        /* optional int32 importance = 2 */ pkgPermissions.get(p).first
+                                ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE,
+                        /* optional int32 visibility = 3 */ DEFAULT_VISIBILITY,
+                        /* optional int32 user_locked_fields = 4 */ DEFAULT_LOCKED_APP_FIELDS,
+                        /* optional bool user_set_importance = 5 */ pkgPermissions.get(p).second,
+                        /* optional FsiState fsi_state = 6 */ 0,
+                        /* optional bool is_fsi_permission_user_set = 7 */ false));
             }
         }
     }
@@ -2288,20 +2276,21 @@
                     if (++totalChannelsPulled > NOTIFICATION_CHANNEL_PULL_LIMIT) {
                         break;
                     }
-                    SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
-                            .setAtomId(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
-                    event.writeInt(r.uid);
-                    event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
-                    event.writeString(channel.getId());
-                    event.writeString(channel.getName().toString());
-                    event.writeString(channel.getDescription());
-                    event.writeInt(channel.getImportance());
-                    event.writeInt(channel.getUserLockedFields());
-                    event.writeBoolean(channel.isDeleted());
-                    event.writeBoolean(channel.getConversationId() != null);
-                    event.writeBoolean(channel.isDemoted());
-                    event.writeBoolean(channel.isImportantConversation());
-                    events.add(event.build());
+                    events.add(FrameworkStatsLog.buildStatsEvent(
+                            PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
+                            /* optional int32 uid = 1 [(is_uid) = true] */ r.uid,
+                            /* optional string channel_id = 2 */ channel.getId(),
+                            /* optional string channel_name = 3 */ channel.getName().toString(),
+                            /* optional string description = 4 */ channel.getDescription(),
+                            /* optional int32 importance = 5 */ channel.getImportance(),
+                            /* optional int32 user_locked_fields = 6 */
+                            channel.getUserLockedFields(),
+                            /* optional bool is_deleted = 7 */ channel.isDeleted(),
+                            /* optional bool is_conversation = 8 */
+                            channel.getConversationId() != null,
+                            /* optional bool is_demoted_conversation = 9 */ channel.isDemoted(),
+                            /* optional bool is_important_conversation = 10 */
+                            channel.isImportantConversation()));
                 }
             }
         }
@@ -2323,16 +2312,15 @@
                     if (++totalGroupsPulled > NOTIFICATION_CHANNEL_GROUP_PULL_LIMIT) {
                         break;
                     }
-                    SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
-                            .setAtomId(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
-                    event.writeInt(r.uid);
-                    event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
-                    event.writeString(groupChannel.getId());
-                    event.writeString(groupChannel.getName().toString());
-                    event.writeString(groupChannel.getDescription());
-                    event.writeBoolean(groupChannel.isBlocked());
-                    event.writeInt(groupChannel.getUserLockedFields());
-                    events.add(event.build());
+                    events.add(FrameworkStatsLog.buildStatsEvent(
+                            PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
+                            /* optional int32 uid = 1 [(is_uid) = true] */ r.uid,
+                            /* optional string group_id = 2 */ groupChannel.getId(),
+                            /* optional string group_name = 3 */ groupChannel.getName().toString(),
+                            /* optional string description = 4 */ groupChannel.getDescription(),
+                            /* optional bool is_blocked = 5 */ groupChannel.isBlocked(),
+                            /* optional int32 user_locked_fields = 6 */
+                            groupChannel.getUserLockedFields()));
                 }
             }
         }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1f5bd3e..a700d32 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,7 +21,6 @@
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
 import static android.service.notification.NotificationServiceProto.ROOT_CONFIG;
-import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
 import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 
@@ -81,6 +80,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -116,7 +116,6 @@
     private final SettingsObserver mSettingsObserver;
     private final AppOpsManager mAppOps;
     private final NotificationManager mNotificationManager;
-    private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
     private ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final ZenModeFiltering mFiltering;
@@ -152,7 +151,6 @@
     private String[] mPriorityOnlyDndExemptPackages;
 
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders,
-            SysUiStatsEvent.BuilderFactory statsEventBuilderFactory,
             SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
             ZenModeEventLogger zenModeEventLogger) {
         mContext = context;
@@ -174,7 +172,6 @@
         mFiltering = new ZenModeFiltering(mContext);
         mConditions = new ZenModeConditions(this, conditionProviders);
         mServiceConfig = conditionProviders.getConfig();
-        mStatsEventBuilderFactory = statsEventBuilderFactory;
         mFlagResolver = flagResolver;
         mZenModeEventLogger = zenModeEventLogger;
     }
@@ -1104,8 +1101,11 @@
                     .allowAlarms(true)
                     .allowMedia(true)
                     .build());
-        } else {
+        } else if (rule.zenPolicy != null) {
             policy.apply(rule.zenPolicy);
+        } else {
+            // active rule with no specified policy inherits the default settings
+            policy.apply(mConfig.toZenPolicy());
         }
     }
 
@@ -1314,17 +1314,14 @@
             for (int i = 0; i < numConfigs; i++) {
                 final int user = mConfigs.keyAt(i);
                 final ZenModeConfig config = mConfigs.valueAt(i);
-                SysUiStatsEvent.Builder data = mStatsEventBuilderFactory.newBuilder()
-                        .setAtomId(DND_MODE_RULE)
-                        .writeInt(user)
-                        .writeBoolean(config.manualRule != null) // enabled
-                        .writeBoolean(config.areChannelsBypassingDnd)
-                        .writeInt(ROOT_CONFIG)
-                        .writeString("") // name, empty for root config
-                        .writeInt(Process.SYSTEM_UID) // system owns root config
-                        .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
-                        .writeByteArray(config.toZenPolicy().toProto());
-                events.add(data.build());
+                events.add(FrameworkStatsLog.buildStatsEvent(DND_MODE_RULE,
+                        /* optional int32 user = 1 */ user,
+                        /* optional bool enabled = 2 */ config.manualRule != null,
+                        /* optional bool channels_bypassing = 3 */ config.areChannelsBypassingDnd,
+                        /* optional LoggedZenMode zen_mode = 4 */ ROOT_CONFIG,
+                        /* optional string id = 5 */ "", // empty for root config
+                        /* optional int32 uid = 6 */ Process.SYSTEM_UID, // system owns root config
+                        /* optional DNDPolicyProto policy = 7 */ config.toZenPolicy().toProto()));
                 if (config.manualRule != null) {
                     ruleToProtoLocked(user, config.manualRule, true, events);
                 }
@@ -1355,21 +1352,18 @@
         }
 
         SysUiStatsEvent.Builder data;
-        data = mStatsEventBuilderFactory.newBuilder()
-                .setAtomId(DND_MODE_RULE)
-                .writeInt(user)
-                .writeBoolean(rule.enabled)
-                .writeBoolean(false) // channels_bypassing unused for rules
-                .writeInt(rule.zenMode)
-                .writeString(id)
-                .writeInt(getPackageUid(pkg, user))
-                .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
         byte[] policyProto = new byte[]{};
         if (rule.zenPolicy != null) {
             policyProto = rule.zenPolicy.toProto();
         }
-        data.writeByteArray(policyProto);
-        events.add(data.build());
+        events.add(FrameworkStatsLog.buildStatsEvent(DND_MODE_RULE,
+                /* optional int32 user = 1 */ user,
+                /* optional bool enabled = 2 */ rule.enabled,
+                /* optional bool channels_bypassing = 3 */ false, // unused for rules
+                /* optional android.stats.dnd.ZenMode zen_mode = 4 */ rule.zenMode,
+                /* optional string id = 5 */ id,
+                /* optional int32 uid = 6 */ getPackageUid(pkg, user),
+                /* optional DNDPolicyProto policy = 7 */ policyProto));
     }
 
     private int getPackageUid(String pkg, int user) {
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 1908e4d..dcac8c9 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -13,3 +13,10 @@
   description: "This flag controls the polite notification feature"
   bug: "270456865"
 }
+
+flag {
+  name: "refactor_attention_helper"
+  namespace: "systemui"
+  description: "This flag controls the refactoring of NMS to NotificationAttentionHelper"
+  bug: "291907312"
+}
diff --git a/services/core/java/com/android/server/pm/ArchiveManager.java b/services/core/java/com/android/server/pm/ArchiveManager.java
deleted file mode 100644
index 5435206..0000000
--- a/services/core/java/com/android/server/pm/ArchiveManager.java
+++ /dev/null
@@ -1,170 +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.server.pm;
-
-import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.IntentSender;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.os.Binder;
-import android.os.UserHandle;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.pm.pkg.ArchiveState;
-import com.android.server.pm.pkg.ArchiveState.ArchiveActivityInfo;
-import com.android.server.pm.pkg.PackageStateInternal;
-
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Responsible archiving apps and returning information about archived apps.
- *
- * <p> An archived app is in a state where the app is not fully on the device. APKs are removed
- * while the data directory is kept. Archived apps are included in the list of launcher apps where
- * tapping them re-installs the full app.
- */
-final class ArchiveManager {
-
-    private final Context mContext;
-    private final PackageManagerService mPm;
-
-    @Nullable
-    private LauncherApps mLauncherApps;
-
-    ArchiveManager(Context context, PackageManagerService mPm) {
-        this.mContext = context;
-        this.mPm = mPm;
-    }
-
-    void archiveApp(
-            @NonNull String packageName,
-            @NonNull String callerPackageName,
-            @NonNull UserHandle user,
-            @NonNull IntentSender intentSender) throws PackageManager.NameNotFoundException {
-        Objects.requireNonNull(packageName);
-        Objects.requireNonNull(callerPackageName);
-        Objects.requireNonNull(user);
-        Objects.requireNonNull(intentSender);
-
-        Computer snapshot = mPm.snapshotComputer();
-        int callingUid = Binder.getCallingUid();
-        int userId = user.getIdentifier();
-        String callingPackageName = snapshot.getNameForUid(callingUid);
-        snapshot.enforceCrossUserPermission(callingUid, userId, true, true,
-                "archiveApp");
-        verifyCaller(callerPackageName, callingPackageName);
-        PackageStateInternal ps = getPackageState(packageName, snapshot, callingUid, user);
-        verifyInstaller(packageName, ps.getInstallSource());
-
-        List<LauncherActivityInfo> mainActivities = getLauncherApps().getActivityList(
-                ps.getPackageName(),
-                new UserHandle(userId));
-        // TODO(b/291569242) Verify that this list is not empty and return failure with intentsender
-
-        storeArchiveState(ps, mainActivities, userId);
-
-        // TODO(b/278553670) Add special strings for the delete dialog
-        mPm.mInstallerService.uninstall(
-                new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
-                callerPackageName, DELETE_KEEP_DATA, intentSender, userId);
-    }
-
-    @NonNull
-    private static PackageStateInternal getPackageState(String packageName,
-            Computer snapshot, int callingUid, UserHandle user)
-            throws PackageManager.NameNotFoundException {
-        PackageStateInternal ps = snapshot.getPackageStateFiltered(packageName, callingUid,
-                user.getIdentifier());
-        if (ps == null) {
-            throw new PackageManager.NameNotFoundException(
-                    TextUtils.formatSimple("Package %s not found.", packageName));
-        }
-        return ps;
-    }
-
-    private LauncherApps getLauncherApps() {
-        if (mLauncherApps == null) {
-            mLauncherApps = mContext.getSystemService(LauncherApps.class);
-        }
-        return mLauncherApps;
-    }
-
-    private void storeArchiveState(PackageStateInternal ps,
-            List<LauncherActivityInfo> mainActivities, int userId)
-            throws PackageManager.NameNotFoundException {
-        List<ArchiveActivityInfo> activityInfos = new ArrayList<>();
-        for (int i = 0; i < mainActivities.size(); i++) {
-            // TODO(b/278553670) Extract and store launcher icons
-            ArchiveActivityInfo activityInfo = new ArchiveActivityInfo(
-                    mainActivities.get(i).getLabel().toString(),
-                    Path.of("/TODO"), null);
-            activityInfos.add(activityInfo);
-        }
-
-        InstallSource installSource = ps.getInstallSource();
-        String installerPackageName = installSource.mUpdateOwnerPackageName != null
-                ? installSource.mUpdateOwnerPackageName : installSource.mInstallerPackageName;
-
-        synchronized (mPm.mLock) {
-            getPackageSetting(ps.getPackageName(), userId).modifyUserState(userId).setArchiveState(
-                    new ArchiveState(activityInfos, installerPackageName));
-        }
-    }
-
-    @NonNull
-    @GuardedBy("mPm.mLock")
-    private PackageSetting getPackageSetting(String packageName, int userId)
-            throws PackageManager.NameNotFoundException {
-        PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
-        if (ps == null || !ps.getUserStateOrDefault(userId).isInstalled()) {
-            throw new PackageManager.NameNotFoundException(
-                    TextUtils.formatSimple("Package %s not found.", packageName));
-        }
-        return ps;
-    }
-
-    private static void verifyCaller(String callerPackageName, String callingPackageName) {
-        if (!TextUtils.equals(callingPackageName, callerPackageName)) {
-            throw new SecurityException(
-                    TextUtils.formatSimple(
-                            "The callerPackageName %s set by the caller doesn't match the "
-                                    + "caller's own package name %s.",
-                            callerPackageName,
-                            callingPackageName));
-        }
-    }
-
-    private static void verifyInstaller(String packageName, InstallSource installSource) {
-        // TODO(b/291060290) Verify installer supports unarchiving
-        if (installSource.mUpdateOwnerPackageName == null
-                && installSource.mInstallerPackageName == null) {
-            throw new SecurityException(
-                    TextUtils.formatSimple("No installer found to archive app %s.",
-                            packageName));
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 1cfc7d7..69a6c13 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -33,6 +33,7 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_APEX;
+import static android.content.pm.PackageManager.MATCH_ARCHIVED_PACKAGES;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
@@ -1507,7 +1508,7 @@
                     resolveExternalPackageName(p);
 
             return packageInfo;
-        } else if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
+        } else if ((flags & (MATCH_UNINSTALLED_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0
                 && PackageUserStateUtils.isAvailable(state, flags)) {
             PackageInfo pi = new PackageInfo();
             pi.packageName = ps.getPackageName();
@@ -1516,6 +1517,7 @@
             pi.sharedUserId = (sharedUser != null) ? sharedUser.getName() : null;
             pi.firstInstallTime = state.getFirstInstallTimeMillis();
             pi.lastUpdateTime = ps.getLastUpdateTime();
+            pi.isArchived = isArchived(state);
 
             ApplicationInfo ai = new ApplicationInfo();
             ai.packageName = ps.getPackageName();
@@ -1614,7 +1616,7 @@
 
             return generatePackageInfo(ps, flags, userId);
         }
-        if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
+        if (!matchFactoryOnly && (flags & (MATCH_KNOWN_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0) {
             final PackageStateInternal ps = mSettings.getPackage(packageName);
             if (ps == null) return null;
             if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
@@ -1678,9 +1680,11 @@
         final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
         final boolean listApex = (flags & MATCH_APEX) != 0;
         final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
+        // Only list archived apps, not fully uninstalled ones. Other entries are unaffected.
+        final boolean listArchivedOnly = !listUninstalled && (flags & MATCH_ARCHIVED_PACKAGES) != 0;
 
         ArrayList<PackageInfo> list;
-        if (listUninstalled) {
+        if (listUninstalled || listArchivedOnly) {
             list = new ArrayList<>(mSettings.getPackages().size());
             for (PackageStateInternal ps : mSettings.getPackages().values()) {
                 if (listFactory) {
@@ -1696,6 +1700,9 @@
                 if (!listApex && ps.getPkg() != null && ps.getPkg().isApex()) {
                     continue;
                 }
+                if (listArchivedOnly && !isArchived(ps.getUserStateOrDefault(userId))) {
+                    continue;
+                }
                 if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
                     continue;
                 }
@@ -1739,6 +1746,13 @@
         return new ParceledListSlice<>(list);
     }
 
+    // TODO(b/288142708) Check for userState.isInstalled() here once this bug is fixed.
+    // If an app has isInstalled() == true - it should not be filtered above in any case, currently
+    // it is.
+    private static boolean isArchived(PackageUserStateInternal userState) {
+        return userState.getArchiveState() != null;
+    }
+
     public final ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
             int sourceUserId, int targetUserId) {
         ResolveInfo forwardingResolveInfo = new ResolveInfo();
@@ -2612,7 +2626,7 @@
                 return UserHandle.getUid(userId, p.getUid());
             }
         }
-        if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
+        if ((flags & (MATCH_KNOWN_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0) {
             final PackageStateInternal ps = mSettings.getPackage(packageName);
             if (ps != null && PackageStateUtils.isMatch(ps, flags)
                     && !shouldFilterApplication(ps, callingUid, userId)) {
@@ -3671,7 +3685,7 @@
                         ps.getAppId()));
             }
         }
-        if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
+        if ((flags & (MATCH_KNOWN_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0) {
             if (PackageStateUtils.isMatch(ps, flags)
                     && !shouldFilterApplication(ps, callingUid, userId)) {
                 return mPermissionManager.getGidsForUid(
@@ -4525,7 +4539,8 @@
         flags = updateFlagsForPackage(flags, userId);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */,
                 false /* checkShell */, "get packages holding permissions");
-        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
+        final boolean listUninstalled =
+                (flags & (MATCH_KNOWN_PACKAGES | MATCH_ARCHIVED_PACKAGES)) != 0;
 
         ArrayList<PackageInfo> list = new ArrayList<>();
         boolean[] tmpBools = new boolean[permissions.length];
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 66a1703..967998a 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -20,12 +20,10 @@
 import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
 import static android.content.pm.PackageManager.DELETE_SUCCEEDED;
 import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
-import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
-import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
@@ -66,20 +64,20 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.ArchiveState;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageUserState;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import dalvik.system.VMRuntime;
 
-import java.util.Collections;
 import java.util.List;
 
 /**
  * Deletes a package. Uninstall if installed, or at least deletes the base directory if it's called
  * from a failed installation. Fixes user state after deletion.
  * Handles special treatments to system apps.
- * Relies on RemovePackageHelper to clear internal data structures.
+ * Relies on RemovePackageHelper to clear internal data structures and remove app data.
  */
 final class DeletePackageHelper {
     private static final boolean DEBUG_CLEAN_APKS = false;
@@ -90,24 +88,17 @@
     private final UserManagerInternal mUserManagerInternal;
     private final PermissionManagerServiceInternal mPermissionManager;
     private final RemovePackageHelper mRemovePackageHelper;
-    private final AppDataHelper mAppDataHelper;
 
     // TODO(b/198166813): remove PMS dependency
-    DeletePackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper,
-            AppDataHelper appDataHelper) {
+    DeletePackageHelper(PackageManagerService pm, RemovePackageHelper removePackageHelper) {
         mPm = pm;
         mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
         mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
         mRemovePackageHelper = removePackageHelper;
-        mAppDataHelper = appDataHelper;
     }
 
     DeletePackageHelper(PackageManagerService pm) {
-        mPm = pm;
-        mAppDataHelper = new AppDataHelper(mPm);
-        mUserManagerInternal = mPm.mInjector.getUserManagerInternal();
-        mPermissionManager = mPm.mInjector.getPermissionManagerServiceInternal();
-        mRemovePackageHelper = new RemovePackageHelper(mPm, mAppDataHelper);
+        this(pm, new RemovePackageHelper(pm));
     }
 
     /**
@@ -444,6 +435,12 @@
         }
 
         final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier();
+        if (outInfo != null) {
+            // Remember which users are affected, before the installed states are modified
+            outInfo.mRemovedUsers = (systemApp || userId == UserHandle.USER_ALL)
+                    ? ps.queryInstalledUsers(allUserHandles, /* installed= */true)
+                    : new int[]{userId};
+        }
 
         if ((!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)
                 && userId != UserHandle.USER_ALL) {
@@ -454,7 +451,7 @@
             // semantics than normal for uninstalling system apps.
             final boolean clearPackageStateAndReturn;
             synchronized (mPm.mLock) {
-                markPackageUninstalledForUserLPw(ps, user);
+                markPackageUninstalledForUserLPw(ps, user, flags);
                 if (!systemApp) {
                     // Do not uninstall the APK if an app should be cached
                     boolean keepUninstalledPackage =
@@ -484,7 +481,7 @@
                 }
             }
             if (clearPackageStateAndReturn) {
-                clearPackageStateForUserLIF(ps, userId, outInfo, flags);
+                mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, outInfo, flags);
                 mPm.scheduleWritePackageRestrictions(user);
                 return;
             }
@@ -531,55 +528,6 @@
         }
     }
 
-    private void clearPackageStateForUserLIF(PackageSetting ps, int userId,
-            PackageRemovedInfo outInfo, int flags) {
-        final AndroidPackage pkg;
-        final SharedUserSetting sus;
-        synchronized (mPm.mLock) {
-            pkg = mPm.mPackages.get(ps.getPackageName());
-            sus = mPm.mSettings.getSharedUserSettingLPr(ps);
-        }
-
-        mAppDataHelper.destroyAppProfilesLIF(pkg);
-
-        final List<AndroidPackage> sharedUserPkgs =
-                sus != null ? sus.getPackages() : Collections.emptyList();
-        final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm);
-        final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManagerInternal.getUserIds()
-                : new int[] {userId};
-        for (int nextUserId : userIds) {
-            if (DEBUG_REMOVE) {
-                Slog.d(TAG, "Updating package:" + ps.getPackageName() + " install state for user:"
-                        + nextUserId);
-            }
-            if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
-                mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
-                        FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
-                ps.setCeDataInode(-1, nextUserId);
-            }
-            mAppDataHelper.clearKeystoreData(nextUserId, ps.getAppId());
-            preferredActivityHelper.clearPackagePreferredActivities(ps.getPackageName(),
-                    nextUserId);
-            mPm.mDomainVerificationManager.clearPackageForUser(ps.getPackageName(), nextUserId);
-        }
-        mPermissionManager.onPackageUninstalled(ps.getPackageName(), ps.getAppId(), ps, pkg,
-                sharedUserPkgs, userId);
-
-        if (outInfo != null) {
-            if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
-                outInfo.mDataRemoved = true;
-            }
-            outInfo.mRemovedPackage = ps.getPackageName();
-            outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
-            outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibraryName() != null;
-            outInfo.mRemovedAppId = ps.getAppId();
-            outInfo.mRemovedUsers = userIds;
-            outInfo.mBroadcastUsers = userIds;
-            outInfo.mIsExternal = ps.isExternalStorage();
-            outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
-        }
-    }
-
     @GuardedBy("mPm.mInstallLock")
     private void deleteInstalledPackageLIF(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
@@ -607,7 +555,7 @@
     }
 
     @GuardedBy("mPm.mLock")
-    private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user) {
+    private void markPackageUninstalledForUserLPw(PackageSetting ps, UserHandle user, int flags) {
         final int[] userIds = (user == null || user.getIdentifier() == UserHandle.USER_ALL)
                 ? mUserManagerInternal.getUserIds()
                 : new int[] {user.getIdentifier()};
@@ -616,6 +564,12 @@
                 Slog.d(TAG, "Marking package:" + ps.getPackageName()
                         + " uninstalled for user:" + nextUserId);
             }
+            // Preserve ArchiveState if this is not a full uninstall
+            ArchiveState archiveState =
+                    (flags & DELETE_KEEP_DATA) == 0
+                            ? null
+                            : ps.getUserStateOrDefault(nextUserId).getArchiveState();
+
             ps.setUserState(nextUserId,
                     ps.getCeDataInode(nextUserId),
                     COMPONENT_ENABLED_STATE_DEFAULT,
@@ -636,7 +590,7 @@
                     null /*splashScreenTheme*/,
                     0 /*firstInstallTime*/,
                     PackageManager.USER_MIN_ASPECT_RATIO_UNSET,
-                    null /*archiveState*/);
+                    archiveState);
         }
         mPm.mSettings.writeKernelMappingLPr(ps);
     }
@@ -682,7 +636,6 @@
             // Preserve data by setting flag
             flags |= PackageManager.DELETE_KEEP_DATA;
         }
-
         synchronized (mPm.mInstallLock) {
             deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, outInfo,
                     writeSettings);
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index f3ea42e..2a00a44 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -619,7 +619,7 @@
         pw.println("    --checkin: dump for a checkin");
         pw.println("    -f: print details of intent filters");
         pw.println("    -h: print this help");
-        pw.println("    ---proto: dump data to proto");
+        pw.println("    --proto: dump data to proto");
         pw.println("    --all-components: include all component names in package dump");
         pw.println("    --include-apex: includes the apex packages in package dump");
         pw.println("  cmd may be one of:");
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
index 76203ac..8f7b721 100644
--- a/services/core/java/com/android/server/pm/IPackageManagerBase.java
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -30,6 +30,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageArchiverService;
 import android.content.pm.IPackageDeleteObserver;
 import android.content.pm.IPackageDeleteObserver2;
 import android.content.pm.IPackageInstaller;
@@ -99,6 +100,9 @@
     private final PackageInstallerService mInstallerService;
 
     @NonNull
+    private final PackageArchiverService mPackageArchiverService;
+
+    @NonNull
     private final PackageProperty mPackageProperty;
 
     @NonNull
@@ -127,7 +131,8 @@
             @Nullable ComponentName instantAppResolverSettingsComponent,
             @NonNull String requiredSupplementalProcessPackage,
             @Nullable String servicesExtensionPackageName,
-            @Nullable String sharedSystemSharedLibraryPackageName) {
+            @Nullable String sharedSystemSharedLibraryPackageName,
+            @NonNull PackageArchiverService packageArchiverService) {
         mService = service;
         mContext = context;
         mDexOptHelper = dexOptHelper;
@@ -143,6 +148,7 @@
         mRequiredSupplementalProcessPackage = requiredSupplementalProcessPackage;
         mServicesExtensionPackageName = servicesExtensionPackageName;
         mSharedSystemSharedLibraryPackageName = sharedSystemSharedLibraryPackageName;
+        mPackageArchiverService = packageArchiverService;
     }
 
     protected Computer snapshot() {
@@ -616,6 +622,12 @@
 
     @Override
     @Deprecated
+    public final IPackageArchiverService getPackageArchiverService() {
+        return mPackageArchiverService;
+    }
+
+    @Override
+    @Deprecated
     public final void getPackageSizeInfo(final String packageName, int userId,
             final IPackageStatsObserver observer) {
         throw new UnsupportedOperationException(
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 3e18387..2712fa7 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -44,7 +44,6 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
-
 import static com.android.server.pm.DexOptHelper.useArtService;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -1144,8 +1143,15 @@
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         final ParsedPackage parsedPackage;
         try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
-            parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
-            AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
+            if (request.getPackageLite() == null || !request.isArchived()) {
+                // TODO: pass packageLite from install request instead of reparsing the package
+                parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
+                AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
+            } else {
+                // Archived install mode, no APK.
+                parsedPackage = pp.parsePackageFromPackageLite(request.getPackageLite(),
+                        parseFlags);
+            }
         } catch (PackageManagerException e) {
             throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
@@ -1547,6 +1553,7 @@
                     // TODO: Are these system flags actually set properly at this stage?
                     boolean isUpdatedSystemAppInferred =
                             pkgSetting != null && pkgSetting.isSystem();
+                    // derivePackageAbi works OK for archived packages despite logging some errors.
                     final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                             derivedAbi = mPackageAbiHelper.derivePackageAbi(parsedPackage,
                             systemApp, (isUpdatedSystemAppFromExistingSetting
@@ -1582,7 +1589,8 @@
 
         final PackageFreezer freezer =
                 freezePackageForInstall(pkgName, UserHandle.USER_ALL, installFlags,
-                        "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED);
+                        "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED, request);
+
         boolean shouldCloseFreezerBeforeReturn = true;
         try {
             final PackageState oldPackageState;
@@ -2032,11 +2040,11 @@
     }
 
     private PackageFreezer freezePackageForInstall(String packageName, int userId, int installFlags,
-            String killReason, int exitInfoReason) {
+            String killReason, int exitInfoReason, InstallRequest request) {
         if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
-            return new PackageFreezer(mPm);
+            return new PackageFreezer(mPm, request);
         } else {
-            return mPm.freezePackage(packageName, userId, killReason, exitInfoReason);
+            return mPm.freezePackage(packageName, userId, killReason, exitInfoReason, request);
         }
     }
 
@@ -3207,7 +3215,7 @@
             try (PackageFreezer freezer =
                          mPm.freezePackage(stubPkg.getPackageName(), UserHandle.USER_ALL,
                                  "setEnabledSetting",
-                                 ApplicationExitInfo.REASON_PACKAGE_UPDATED)) {
+                                 ApplicationExitInfo.REASON_PACKAGE_UPDATED, null /* request */)) {
                 pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
                 mAppDataHelper.prepareAppDataAfterInstallLIF(pkg);
                 synchronized (mPm.mLock) {
@@ -3231,7 +3239,8 @@
                 try (PackageFreezer freezer =
                              mPm.freezePackage(stubPkg.getPackageName(), UserHandle.USER_ALL,
                                      "setEnabledSetting",
-                                     ApplicationExitInfo.REASON_PACKAGE_UPDATED)) {
+                                     ApplicationExitInfo.REASON_PACKAGE_UPDATED,
+                                     null /* request */)) {
                     synchronized (mPm.mLock) {
                         // NOTE: Ensure the system package is enabled; even for a compressed stub.
                         // If we don't, installing the system package fails during scan
@@ -3545,7 +3554,7 @@
                 logCriticalInfo(Log.WARN, "System package " + packageName
                         + " no longer exists; its data will be wiped");
                 mInjector.getHandler().post(
-                        () -> mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false));
+                        () -> mRemovePackageHelper.removePackageData(ps, userIds));
                 expectingBetter.put(ps.getPackageName(), ps.getPath());
             } else {
                 // we still have a disabled system package, but, it still might have
@@ -3620,7 +3629,7 @@
             // partition], completely remove the package data.
             final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
             if (ps != null && mPm.mPackages.get(packageName) == null) {
-                mRemovePackageHelper.removePackageData(ps, userIds, null, 0, false);
+                mRemovePackageHelper.removePackageData(ps, userIds);
             }
             logCriticalInfo(Log.WARN, msg);
         }
@@ -4291,7 +4300,8 @@
                                 + " name: " + pkgSetting.getPackageName());
                 try (@SuppressWarnings("unused") PackageFreezer freezer = mPm.freezePackage(
                         parsedPackage.getPackageName(), UserHandle.USER_ALL,
-                        "scanPackageInternalLI", ApplicationExitInfo.REASON_OTHER)) {
+                        "scanPackageInternalLI", ApplicationExitInfo.REASON_OTHER,
+                        null /* request */)) {
                     DeletePackageHelper deletePackageHelper = new DeletePackageHelper(mPm);
                     deletePackageHelper.deletePackageLIF(parsedPackage.getPackageName(), null, true,
                             mPm.mUserManager.getUserIds(), 0, null, false);
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 6fc14e8..e1cfc41 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -21,7 +21,6 @@
 import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.os.Process.INVALID_UID;
-
 import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
 import static com.android.server.pm.PackageManagerService.TAG;
 
@@ -35,6 +34,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
+import android.content.pm.parsing.PackageLite;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Process;
@@ -93,6 +93,8 @@
     private int[] mNewUsers;
     @Nullable
     private AndroidPackage mPkg;
+    @Nullable
+    private PackageLite mPackageLite;
     private int mReturnCode;
     private int mInternalErrorCode;
     @Nullable
@@ -142,6 +144,7 @@
                 params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
                 params.mDataLoaderType, params.mPackageSource,
                 params.mApplicationEnabledSettingPersistent);
+        mPackageLite = params.mPackageLite;
         mPackageMetrics = new PackageMetrics(this);
         mIsInstallInherit = params.mIsInherit;
         mSessionId = params.mSessionId;
@@ -306,6 +309,11 @@
     }
 
     @Nullable
+    public PackageLite getPackageLite() {
+        return mPackageLite;
+    }
+
+    @Nullable
     public String getTraceMethod() {
         return mInstallArgs == null ? null : mInstallArgs.mTraceMethod;
     }
@@ -318,6 +326,10 @@
         return mRemovedInfo != null && mRemovedInfo.mRemovedPackage != null;
     }
 
+    public boolean isArchived() {
+        return PackageInstallerSession.isArchivedInstallation(getInstallFlags());
+    }
+
     @Nullable
     public String getRemovedPackage() {
         return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null;
@@ -831,4 +843,16 @@
             }
         }
     }
+
+    public void onFreezeStarted() {
+        if (mPackageMetrics != null) {
+            mPackageMetrics.onStepStarted(PackageMetrics.STEP_FREEZE_INSTALL);
+        }
+    }
+
+    public void onFreezeCompleted() {
+        if (mPackageMetrics != null) {
+            mPackageMetrics.onStepFinished(PackageMetrics.STEP_FREEZE_INSTALL);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 9ac983d..6233c9b 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -29,6 +29,7 @@
 import android.os.CreateAppDataResult;
 import android.os.IBinder;
 import android.os.IInstalld;
+import android.os.ParcelFileDescriptor;
 import android.os.ReconcileSdkDataArgs;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1161,6 +1162,55 @@
         }
     }
 
+    /**
+     * Returns an auth token for the provided writable FD.
+     *
+     * @param authFd a file descriptor to proof that the caller can write to the file.
+     * @param appUid uid of the calling app.
+     * @param userId id of the user whose app file to enable fs-verity.
+     *
+     * @return authToken, or null if a remote call shouldn't be continued. See {@link
+     * #checkBeforeRemote}.
+     *
+     * @throws InstallerException if the remote call failed.
+     */
+    public IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken(
+            ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId)
+            throws InstallerException {
+        if (!checkBeforeRemote()) {
+            return null;
+        }
+        try {
+            return mInstalld.createFsveritySetupAuthToken(authFd, appUid, userId);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
+    /**
+     * Enables fs-verity to the given app file.
+     *
+     * @param authToken a token previously returned from {@link #createFsveritySetupAuthToken}.
+     * @param filePath file path of the package to enable fs-verity.
+     * @param packageName name of the package.
+     *
+     * @return 0 if the operation was successful, otherwise {@code errno}.
+     *
+     * @throws InstallerException if the remote call failed (e.g. see {@link #checkBeforeRemote}).
+     */
+    public int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath,
+            String packageName) throws InstallerException {
+        if (!checkBeforeRemote()) {
+            throw new InstallerException("fs-verity wasn't enabled with an isolated installer");
+        }
+        BlockGuard.getVmPolicy().onPathAccess(filePath);
+        try {
+            return mInstalld.enableFsverity(authToken, filePath, packageName);
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     public static class InstallerException extends Exception {
         public InstallerException(String detailMessage) {
             super(detailMessage);
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 30a23bf..fe6a8a1 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -543,7 +543,6 @@
             mInstallPackageHelper.installPackagesTraced(installRequests);
 
             for (InstallRequest request : installRequests) {
-                request.onInstallCompleted();
                 doPostInstall(request);
             }
         }
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 01c2734..148e0df 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -147,7 +147,8 @@
         final PackageFreezer freezer;
         synchronized (mPm.mLock) {
             freezer = mPm.freezePackage(packageName, UserHandle.USER_ALL,
-                    "movePackageInternal", ApplicationExitInfo.REASON_USER_REQUESTED);
+                    "movePackageInternal", ApplicationExitInfo.REASON_USER_REQUESTED,
+                    null /* request */);
         }
 
         final Bundle extras = new Bundle();
diff --git a/services/core/java/com/android/server/pm/PackageArchiverService.java b/services/core/java/com/android/server/pm/PackageArchiverService.java
new file mode 100644
index 0000000..c7f067b
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageArchiverService.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
+import static android.os.PowerExemptionManager.REASON_PACKAGE_UNARCHIVE;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.IPackageArchiverService;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageArchiver;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.ParcelableException;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.pm.pkg.ArchiveState;
+import com.android.server.pm.pkg.ArchiveState.ArchiveActivityInfo;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageUserStateInternal;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Responsible archiving apps and returning information about archived apps.
+ *
+ * <p> An archived app is in a state where the app is not fully on the device. APKs are removed
+ * while the data directory is kept. Archived apps are included in the list of launcher apps where
+ * tapping them re-installs the full app.
+ */
+public class PackageArchiverService extends IPackageArchiverService.Stub {
+
+    /**
+     * The maximum time granted for an app store to start a foreground service when unarchival
+     * is requested.
+     */
+    // TODO(b/297358628) Make this configurable through a flag.
+    private static final int DEFAULT_UNARCHIVE_FOREGROUND_TIMEOUT_MS = 120 * 1000;
+
+    private final Context mContext;
+    private final PackageManagerService mPm;
+
+    @Nullable
+    private LauncherApps mLauncherApps;
+
+    public PackageArchiverService(Context context, PackageManagerService mPm) {
+        this.mContext = context;
+        this.mPm = mPm;
+    }
+
+    @Override
+    public void requestArchive(
+            @NonNull String packageName,
+            @NonNull String callerPackageName,
+            @NonNull IntentSender intentSender,
+            @NonNull UserHandle userHandle) {
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(callerPackageName);
+        Objects.requireNonNull(intentSender);
+        Objects.requireNonNull(userHandle);
+
+        Computer snapshot = mPm.snapshotComputer();
+        int userId = userHandle.getIdentifier();
+        int binderUid = Binder.getCallingUid();
+        int providedUid = snapshot.getPackageUid(callerPackageName, 0, userId);
+        snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
+                "archiveApp");
+        verifyCaller(providedUid, binderUid);
+        ArchiveState archiveState;
+        try {
+            archiveState = createArchiveState(packageName, userId);
+            // TODO(b/282952870) Should be reverted if uninstall fails/cancels
+            storeArchiveState(packageName, archiveState, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new ParcelableException(e);
+        }
+
+        // TODO(b/278553670) Add special strings for the delete dialog
+        mPm.mInstallerService.uninstall(
+                new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+                callerPackageName, DELETE_KEEP_DATA, intentSender, userId);
+    }
+
+    /**
+     * Creates archived state for the package and user.
+     */
+    public ArchiveState createArchiveState(String packageName, int userId)
+            throws PackageManager.NameNotFoundException {
+        PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(),
+                Binder.getCallingUid(), userId);
+        String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
+        verifyInstaller(responsibleInstallerPackage);
+
+        List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps, userId);
+        List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>();
+        for (int i = 0; i < mainActivities.size(); i++) {
+            // TODO(b/278553670) Extract and store launcher icons
+            ArchiveActivityInfo activityInfo = new ArchiveActivityInfo(
+                    mainActivities.get(i).getLabel().toString(),
+                    Path.of("/TODO"), null);
+            archiveActivityInfos.add(activityInfo);
+        }
+
+        return new ArchiveState(archiveActivityInfos, responsibleInstallerPackage);
+    }
+
+    private void verifyInstaller(String installerPackage)
+            throws PackageManager.NameNotFoundException {
+        if (TextUtils.isEmpty(installerPackage)) {
+            throw new PackageManager.NameNotFoundException("No installer found");
+        }
+        if (!verifySupportsUnarchival(installerPackage)) {
+            throw new PackageManager.NameNotFoundException("Installer does not support unarchival");
+        }
+    }
+
+    /**
+     * @return true if installerPackage support unarchival:
+     * - has an action Intent.ACTION_UNARCHIVE_PACKAGE,
+     * - has permissions to install packages.
+     */
+    public boolean verifySupportsUnarchival(String installerPackage) {
+        // TODO(b/278553670) Check if installerPackage supports unarchival.
+        return true;
+    }
+
+    @Override
+    public void requestUnarchive(
+            @NonNull String packageName,
+            @NonNull String callerPackageName,
+            @NonNull UserHandle userHandle) {
+        Objects.requireNonNull(packageName);
+        Objects.requireNonNull(callerPackageName);
+        Objects.requireNonNull(userHandle);
+
+        Computer snapshot = mPm.snapshotComputer();
+        int userId = userHandle.getIdentifier();
+        int binderUid = Binder.getCallingUid();
+        int providedUid = snapshot.getPackageUid(callerPackageName, 0, userId);
+        snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
+                "unarchiveApp");
+        verifyCaller(providedUid, binderUid);
+        PackageStateInternal ps;
+        try {
+            ps = getPackageState(packageName, snapshot, binderUid, userId);
+            verifyArchived(ps, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new ParcelableException(e);
+        }
+        String installerPackage = getResponsibleInstallerPackage(ps);
+        if (installerPackage == null) {
+            throw new ParcelableException(
+                    new PackageManager.NameNotFoundException(
+                            TextUtils.formatSimple("No installer found to unarchive app %s.",
+                                    packageName)));
+        }
+
+        mPm.mHandler.post(() -> unarchiveInternal(packageName, userHandle, installerPackage));
+    }
+
+    private void verifyArchived(PackageStateInternal ps, int userId)
+            throws PackageManager.NameNotFoundException {
+        PackageUserStateInternal userState = ps.getUserStateOrDefault(userId);
+        // TODO(b/288142708) Check for isInstalled false here too.
+        if (userState.getArchiveState() == null) {
+            throw new PackageManager.NameNotFoundException(
+                    TextUtils.formatSimple("Package %s is not currently archived.",
+                            ps.getPackageName()));
+        }
+    }
+
+    @RequiresPermission(
+            allOf = {
+                    Manifest.permission.INTERACT_ACROSS_USERS,
+                    android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+                    android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+            conditional = true)
+    private void unarchiveInternal(String packageName, UserHandle userHandle,
+            String installerPackage) {
+        int userId = userHandle.getIdentifier();
+        Intent unarchiveIntent = new Intent(Intent.ACTION_UNARCHIVE_PACKAGE);
+        unarchiveIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        unarchiveIntent.putExtra(PackageArchiver.EXTRA_UNARCHIVE_PACKAGE_NAME, packageName);
+        unarchiveIntent.putExtra(PackageArchiver.EXTRA_UNARCHIVE_ALL_USERS,
+                userId == UserHandle.USER_ALL);
+        unarchiveIntent.setPackage(installerPackage);
+
+        // If the unarchival is requested for all users, the current user is used for unarchival.
+        UserHandle userForUnarchival = userId == UserHandle.USER_ALL
+                ? UserHandle.of(mPm.mUserManager.getCurrentUserId())
+                : userHandle;
+        mContext.sendOrderedBroadcastAsUser(
+                unarchiveIntent,
+                userForUnarchival,
+                /* receiverPermission = */ null,
+                AppOpsManager.OP_NONE,
+                createUnarchiveOptions(),
+                /* resultReceiver= */ null,
+                /* scheduler= */ null,
+                /* initialCode= */ 0,
+                /* initialData= */ null,
+                /* initialExtras= */ null);
+    }
+
+    private List<LauncherActivityInfo> getLauncherActivityInfos(PackageStateInternal ps,
+            int userId) throws PackageManager.NameNotFoundException {
+        List<LauncherActivityInfo> mainActivities =
+                Binder.withCleanCallingIdentity(() -> getLauncherApps().getActivityList(
+                        ps.getPackageName(),
+                        new UserHandle(userId)));
+        if (mainActivities.isEmpty()) {
+            throw new PackageManager.NameNotFoundException(
+                    TextUtils.formatSimple("The app %s does not have a main activity.",
+                            ps.getPackageName()));
+        }
+
+        return mainActivities;
+    }
+
+    @RequiresPermission(anyOf = {android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+            android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+            android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND})
+    private Bundle createUnarchiveOptions() {
+        BroadcastOptions options = BroadcastOptions.makeBasic();
+        options.setTemporaryAppAllowlist(getUnarchiveForegroundTimeout(),
+                TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                REASON_PACKAGE_UNARCHIVE, "");
+        return options.toBundle();
+    }
+
+    private static int getUnarchiveForegroundTimeout() {
+        return DEFAULT_UNARCHIVE_FOREGROUND_TIMEOUT_MS;
+    }
+
+    private String getResponsibleInstallerPackage(PackageStateInternal ps) {
+        return TextUtils.isEmpty(ps.getInstallSource().mUpdateOwnerPackageName)
+                ? ps.getInstallSource().mInstallerPackageName
+                : ps.getInstallSource().mUpdateOwnerPackageName;
+    }
+
+    @NonNull
+    private static PackageStateInternal getPackageState(String packageName,
+            Computer snapshot, int callingUid, int userId)
+            throws PackageManager.NameNotFoundException {
+        PackageStateInternal ps = snapshot.getPackageStateFiltered(packageName, callingUid,
+                userId);
+        if (ps == null) {
+            throw new PackageManager.NameNotFoundException(
+                    TextUtils.formatSimple("Package %s not found.", packageName));
+        }
+        return ps;
+    }
+
+    private LauncherApps getLauncherApps() {
+        if (mLauncherApps == null) {
+            mLauncherApps = mContext.getSystemService(LauncherApps.class);
+        }
+        return mLauncherApps;
+    }
+
+    private void storeArchiveState(String packageName, ArchiveState archiveState, int userId)
+            throws PackageManager.NameNotFoundException {
+        synchronized (mPm.mLock) {
+            PackageSetting packageSetting = getPackageSettingLocked(packageName, userId);
+            packageSetting
+                    .modifyUserState(userId)
+                    .setArchiveState(archiveState);
+        }
+    }
+
+    @NonNull
+    @GuardedBy("mPm.mLock")
+    private PackageSetting getPackageSettingLocked(String packageName, int userId)
+            throws PackageManager.NameNotFoundException {
+        PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
+        // Shouldn't happen, we already verify presence of the package in getPackageState()
+        if (ps == null || !ps.getUserStateOrDefault(userId).isInstalled()) {
+            throw new PackageManager.NameNotFoundException(
+                    TextUtils.formatSimple("Package %s not found.", packageName));
+        }
+        return ps;
+    }
+
+    private static void verifyCaller(int providedUid, int binderUid) {
+        if (providedUid != binderUid) {
+            throw new SecurityException(
+                    TextUtils.formatSimple(
+                            "The UID %s of callerPackageName set by the caller doesn't match the "
+                                    + "caller's actual UID %s.",
+                            providedUid,
+                            binderUid));
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index 841b66e..7c56157 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.PackageManager;
 
 import dalvik.system.CloseGuard;
@@ -29,6 +30,8 @@
  * app code/data to prevent the app from running while you're working.
  */
 final class PackageFreezer implements AutoCloseable {
+    @Nullable private InstallRequest mInstallRequest;
+
     private final String mPackageName;
 
     private final AtomicBoolean mClosed = new AtomicBoolean();
@@ -43,18 +46,29 @@
      * {@link PackageManager#INSTALL_DONT_KILL_APP} or
      * {@link PackageManager#DELETE_DONT_KILL_APP}.
      */
-    PackageFreezer(PackageManagerService pm) {
+
+    PackageFreezer(PackageManagerService pm, @Nullable InstallRequest request) {
         mPm = pm;
         mPackageName = null;
         mClosed.set(true);
         mCloseGuard.open("close");
+        mInstallRequest = request;
+        // We only focus on the install Freeze metrics now
+        if (mInstallRequest != null) {
+            mInstallRequest.onFreezeStarted();
+        }
     }
 
     PackageFreezer(String packageName, int userId, String killReason,
-            PackageManagerService pm, int exitInfoReason) {
+            PackageManagerService pm, int exitInfoReason, @Nullable InstallRequest request) {
         mPm = pm;
         mPackageName = packageName;
+        mInstallRequest = request;
         final PackageSetting ps;
+        // We only focus on the install Freeze metrics now
+        if (mInstallRequest != null) {
+            mInstallRequest.onFreezeStarted();
+        }
         synchronized (mPm.mLock) {
             final int refCounts = mPm.mFrozenPackages
                     .getOrDefault(mPackageName, 0 /* defaultValue */) + 1;
@@ -92,5 +106,10 @@
                 }
             }
         }
+        // We only focus on the install Freeze metrics now
+        if (mInstallRequest != null) {
+            mInstallRequest.onFreezeCompleted();
+            mInstallRequest = null;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 83d2f6a..b4ca477 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -93,6 +93,7 @@
                 mPm.mRunningInstalls.delete(msg.arg1);
 
                 request.closeFreezer();
+                request.onInstallCompleted();
                 request.runPostInstallRunnable();
                 if (!request.isInstallExistingForUser()) {
                     mInstallPackageHelper.handlePackagePostInstall(request, didRestore);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java b/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java
new file mode 100644
index 0000000..d40a715
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageInstallerHistoricalSession.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.PackageInstaller.PreapprovalDetails;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.CharArrayWriter;
+import java.io.File;
+
+/**
+ * A historical session object that stores minimal session info.
+ */
+public final class PackageInstallerHistoricalSession {
+    public final int sessionId;
+    public final int userId;
+    private final String mParams;
+    private final long mCreatedMillis;
+
+    private final File mStageDir;
+    private final String mStageCid;
+
+    private final long mUpdatedMillis;
+
+    private final long mCommittedMillis;
+
+    private final int mOriginalInstallerUid;
+
+    private final String mOriginalInstallerPackageName;
+
+    private final int mInstallerUid;
+
+    private final InstallSource mInstallSource;
+
+    private final float mClientProgress;
+
+    private final float mProgress;
+    private final boolean mSealed;
+
+    private final boolean mPreapprovalRequested;
+    private final boolean mCommitted;
+
+    private final boolean mStageDirInUse;
+
+    private final boolean mPermissionsManuallyAccepted;
+
+    private final int mFinalStatus;
+    private final String mFinalMessage;
+
+    private final int mFds;
+    private final int mBridges;
+
+    private final String mPreapprovalDetails;
+    private final int mParentSessionId;
+    private final boolean mDestroyed;
+    private final int[] mChildSessionIds;
+    private final boolean mSessionApplied;
+    private final boolean mSessionReady;
+    private final boolean mSessionFailed;
+    private final int mSessionErrorCode;
+    private final String mSessionErrorMessage;
+
+    PackageInstallerHistoricalSession(int sessionId, int userId, int originalInstallerUid,
+            String originalInstallerPackageName, InstallSource installSource, int installerUid,
+            long createdMillis, long updatedMillis, long committedMillis, File stageDir,
+            String stageCid, float clientProgress, float progress, boolean committed,
+            boolean preapprovalRequested, boolean sealed, boolean permissionsManuallyAccepted,
+            boolean stageDirInUse, boolean destroyed, int fds, int bridges, int finalStatus,
+            String finalMessage, SessionParams params, int parentSessionId,
+            int[] childSessionIds, boolean sessionApplied, boolean sessionFailed,
+            boolean sessionReady, int sessionErrorCode, String sessionErrorMessage,
+            PreapprovalDetails preapprovalDetails) {
+        this.sessionId = sessionId;
+        this.userId = userId;
+        this.mOriginalInstallerUid = originalInstallerUid;
+        this.mOriginalInstallerPackageName = originalInstallerPackageName;
+        this.mInstallSource = installSource;
+        this.mInstallerUid = installerUid;
+        this.mCreatedMillis = createdMillis;
+        this.mUpdatedMillis = updatedMillis;
+        this.mCommittedMillis = committedMillis;
+        this.mStageDir = stageDir;
+        this.mStageCid = stageCid;
+        this.mClientProgress = clientProgress;
+        this.mProgress = progress;
+        this.mCommitted = committed;
+        this.mPreapprovalRequested = preapprovalRequested;
+        this.mSealed = sealed;
+        this.mPermissionsManuallyAccepted = permissionsManuallyAccepted;
+        this.mStageDirInUse = stageDirInUse;
+        this.mDestroyed = destroyed;
+        this.mFds = fds;
+        this.mBridges = bridges;
+        this.mFinalStatus = finalStatus;
+        this.mFinalMessage = finalMessage;
+
+        CharArrayWriter writer = new CharArrayWriter();
+        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "    ");
+        params.dump(pw);
+        this.mParams = writer.toString();
+
+        this.mParentSessionId = parentSessionId;
+        this.mChildSessionIds = childSessionIds;
+        this.mSessionApplied = sessionApplied;
+        this.mSessionFailed = sessionFailed;
+        this.mSessionReady = sessionReady;
+        this.mSessionErrorCode = sessionErrorCode;
+        this.mSessionErrorMessage = sessionErrorMessage;
+        if (preapprovalDetails != null) {
+            this.mPreapprovalDetails = preapprovalDetails.toString();
+        } else {
+            this.mPreapprovalDetails = null;
+        }
+    }
+
+    void dump(IndentingPrintWriter pw) {
+        pw.println("Session " + sessionId + ":");
+        pw.increaseIndent();
+
+        pw.printPair("userId", userId);
+        pw.printPair("mOriginalInstallerUid", mOriginalInstallerUid);
+        pw.printPair("mOriginalInstallerPackageName", mOriginalInstallerPackageName);
+        pw.printPair("installerPackageName", mInstallSource.mInstallerPackageName);
+        pw.printPair("installInitiatingPackageName", mInstallSource.mInitiatingPackageName);
+        pw.printPair("installOriginatingPackageName", mInstallSource.mOriginatingPackageName);
+        pw.printPair("mInstallerUid", mInstallerUid);
+        pw.printPair("createdMillis", mCreatedMillis);
+        pw.printPair("updatedMillis", mUpdatedMillis);
+        pw.printPair("committedMillis", mCommittedMillis);
+        pw.printPair("stageDir", mStageDir);
+        pw.printPair("stageCid", mStageCid);
+        pw.println();
+
+        pw.print(mParams);
+
+        pw.printPair("mClientProgress", mClientProgress);
+        pw.printPair("mProgress", mProgress);
+        pw.printPair("mCommitted", mCommitted);
+        pw.printPair("mPreapprovalRequested", mPreapprovalRequested);
+        pw.printPair("mSealed", mSealed);
+        pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
+        pw.printPair("mStageDirInUse", mStageDirInUse);
+        pw.printPair("mDestroyed", mDestroyed);
+        pw.printPair("mFds", mFds);
+        pw.printPair("mBridges", mBridges);
+        pw.printPair("mFinalStatus", mFinalStatus);
+        pw.printPair("mFinalMessage", mFinalMessage);
+        pw.printPair("mParentSessionId", mParentSessionId);
+        pw.printPair("mChildSessionIds", mChildSessionIds);
+        pw.printPair("mSessionApplied", mSessionApplied);
+        pw.printPair("mSessionFailed", mSessionFailed);
+        pw.printPair("mSessionReady", mSessionReady);
+        pw.printPair("mSessionErrorCode", mSessionErrorCode);
+        pw.printPair("mSessionErrorMessage", mSessionErrorMessage);
+        pw.printPair("mPreapprovalDetails", mPreapprovalDetails);
+        pw.println();
+
+        pw.decreaseIndent();
+    }
+
+    /**
+     * Generates a {@link SessionInfo} object.
+     */
+    public SessionInfo generateInfo() {
+        final SessionInfo info = new SessionInfo();
+        info.sessionId = sessionId;
+        info.userId = userId;
+        info.installerPackageName = mInstallSource.mInstallerPackageName;
+        info.installerAttributionTag = mInstallSource.mInstallerAttributionTag;
+        info.progress = mProgress;
+        info.sealed = mSealed;
+        info.isCommitted = mCommitted;
+        info.isPreapprovalRequested = mPreapprovalRequested;
+
+        info.parentSessionId = mParentSessionId;
+        info.childSessionIds = mChildSessionIds;
+        info.isSessionApplied = mSessionApplied;
+        info.isSessionReady = mSessionReady;
+        info.isSessionFailed = mSessionFailed;
+        info.setSessionErrorCode(mSessionErrorCode, mSessionErrorMessage);
+        info.createdMillis = mCreatedMillis;
+        info.updatedMillis = mUpdatedMillis;
+        info.installerUid = mInstallerUid;
+        return info;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 10cd51a..e360256 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -111,7 +111,6 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.CharArrayWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -230,7 +229,7 @@
 
     /** Historical sessions kept around for debugging purposes */
     @GuardedBy("mSessions")
-    private final List<String> mHistoricalSessions = new ArrayList<>();
+    private final List<PackageInstallerHistoricalSession> mHistoricalSessions = new ArrayList<>();
 
     @GuardedBy("mSessions")
     private final SparseIntArray mHistoricalSessionsByInstaller = new SparseIntArray();
@@ -570,14 +569,11 @@
 
     @GuardedBy("mSessions")
     private void addHistoricalSessionLocked(PackageInstallerSession session) {
-        CharArrayWriter writer = new CharArrayWriter();
-        IndentingPrintWriter pw = new IndentingPrintWriter(writer, "    ");
-        session.dump(pw);
         if (mHistoricalSessions.size() > HISTORICAL_SESSIONS_THRESHOLD) {
             Slog.d(TAG, "Historical sessions size reaches threshold, clear the oldest");
             mHistoricalSessions.subList(0, HISTORICAL_CLEAR_SIZE).clear();
         }
-        mHistoricalSessions.add(writer.toString());
+        mHistoricalSessions.add(session.createHistoricalSession());
 
         int installerUid = session.getInstallerUid();
         // Increment the number of sessions by this installerUid.
@@ -1223,6 +1219,24 @@
         return new ParceledListSlice<>(result);
     }
 
+    ParceledListSlice<SessionInfo> getHistoricalSessions(int userId) {
+        final int callingUid = Binder.getCallingUid();
+        final Computer snapshot = mPm.snapshotComputer();
+        snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions");
+
+        final List<SessionInfo> result = new ArrayList<>();
+        synchronized (mSessions) {
+            for (int i = 0; i < mHistoricalSessions.size(); i++) {
+                final PackageInstallerHistoricalSession session = mHistoricalSessions.get(i);
+                if (userId == UserHandle.USER_ALL || session.userId == userId) {
+                    result.add(session.generateInfo());
+                }
+            }
+        }
+        result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
+        return new ParceledListSlice<>(result);
+    }
+
     @Override
     public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
                 IntentSender statusReceiver, int userId) {
@@ -1837,7 +1851,7 @@
             pw.increaseIndent();
             N = mHistoricalSessions.size();
             for (int i = 0; i < N; i++) {
-                pw.print(mHistoricalSessions.get(i));
+                mHistoricalSessions.get(i).dump(pw);
                 pw.println();
             }
             pw.println();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 923bbab..0dd4111ad 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -31,6 +31,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
 import static android.content.pm.PackageManager.INSTALL_STAGED;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
@@ -39,7 +40,6 @@
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 import static com.android.internal.util.XmlUtils.readBitmapAttribute;
 import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
@@ -52,6 +52,7 @@
 import static com.android.server.pm.PackageInstallerService.prepareStageDir;
 import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.PackageManagerServiceUtils.isInstalledByAdb;
+import static com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
 
 import android.Manifest;
 import android.annotation.AnyThread;
@@ -838,6 +839,10 @@
                 params.dataLoaderParams.getComponentName().getPackageName());
     }
 
+    static boolean isArchivedInstallation(int installFlags) {
+        return (installFlags & PackageManager.INSTALL_ARCHIVED) != 0;
+    }
+
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
@@ -896,6 +901,10 @@
         return isSystemDataLoaderInstallation(this.params);
     }
 
+    private boolean isArchivedInstallation() {
+        return isArchivedInstallation(this.params.installFlags);
+    }
+
     /**
      * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
      */
@@ -1146,6 +1155,41 @@
         if (isIncrementalInstallation() && !IncrementalManager.isAllowed()) {
             throw new IllegalArgumentException("Incremental installation not allowed.");
         }
+
+        if (isArchivedInstallation()) {
+            if (params.mode != SessionParams.MODE_FULL_INSTALL) {
+                throw new IllegalArgumentException(
+                        "Archived installation can only be full install.");
+            }
+            if (!isStreamingInstallation() || !isSystemDataLoaderInstallation()) {
+                throw new IllegalArgumentException(
+                        "Archived installation can only use Streaming System DataLoader.");
+            }
+            if (!TextUtils.isEmpty(params.appPackageName) && !isArchivedInstallationAllowed(
+                    params.appPackageName)) {
+                throw new IllegalArgumentException(
+                        "Archived installation of this package is not allowed.");
+            }
+        }
+    }
+
+    PackageInstallerHistoricalSession createHistoricalSession() {
+        final float progress;
+        final float clientProgress;
+        synchronized (mProgressLock) {
+            progress = mProgress;
+            clientProgress = mClientProgress;
+        }
+        synchronized (mLock) {
+            return new PackageInstallerHistoricalSession(sessionId, userId, mOriginalInstallerUid,
+                    mOriginalInstallerPackageName, mInstallSource, mInstallerUid, createdMillis,
+                    updatedMillis, committedMillis, stageDir, stageCid, clientProgress, progress,
+                    isCommitted(), isPreapprovalRequested(), mSealed, mPermissionsManuallyAccepted,
+                    mStageDirInUse, mDestroyed, mFds.size(), mBridges.size(), mFinalStatus,
+                    mFinalMessage, params, mParentSessionId, getChildSessionIdsLocked(),
+                    mSessionApplied, mSessionFailed, mSessionReady, mSessionErrorCode,
+                    mSessionErrorMessage, mPreapprovalDetails);
+        }
     }
 
     /**
@@ -1462,6 +1506,58 @@
     }
 
     @GuardedBy("mLock")
+    private List<ApkLite> getAddedApkLitesLocked() throws PackageManagerException {
+        if (!isArchivedInstallation()) {
+            List<File> files = getAddedApksLocked();
+            final List<ApkLite> result = new ArrayList<>(files.size());
+
+            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            for (int i = 0, size = files.size(); i < size; ++i) {
+                final ParseResult<ApkLite> parseResult = ApkLiteParseUtils.parseApkLite(
+                        input.reset(), files.get(i),
+                        ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
+                if (parseResult.isError()) {
+                    throw new PackageManagerException(parseResult.getErrorCode(),
+                            parseResult.getErrorMessage(), parseResult.getException());
+                }
+                result.add(parseResult.getResult());
+            }
+
+            return result;
+        }
+
+        InstallationFile[] files = getInstallationFilesLocked();
+        final List<ApkLite> result = new ArrayList<>(files.length);
+
+        for (int i = 0, size = files.length; i < size; ++i) {
+            File file = new File(stageDir, files[i].getName());
+            if (!sAddedApkFilter.accept(file)) {
+                continue;
+            }
+
+            final Metadata metadata;
+            try {
+                metadata = Metadata.fromByteArray(files[i].getMetadata());
+            } catch (IOException e) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Failed to ", e);
+            }
+            if (metadata.getMode() != Metadata.ARCHIVED) {
+                throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE,
+                        "File metadata is not for ARCHIVED package: " + file);
+            }
+
+            var archPkg = metadata.getArchivedPackage();
+            if (archPkg.packageName == null || archPkg.signingDetails == null) {
+                throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE,
+                        "ArchivedPackage does not contain required info: " + file);
+            }
+            result.add(new ApkLite(file.getAbsolutePath(), archPkg));
+        }
+        return result;
+    }
+
+    @GuardedBy("mLock")
     private List<File> getRemovedFilesLocked() {
         String[] names = getNamesLocked();
         return filterFiles(stageDir, names, sRemovedFilter);
@@ -2128,6 +2224,19 @@
     }
 
     /**
+     * Check if this package can be installed archived.
+     */
+    private static boolean isArchivedInstallationAllowed(String packageName) {
+        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        final PackageStateInternal existingPkgSetting = pmi.getPackageStateInternal(packageName);
+        if (existingPkgSetting == null) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Checks if the package can be installed on IncFs.
      */
     private static boolean isIncrementalInstallationAllowed(String packageName) {
@@ -2732,9 +2841,18 @@
                 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                         "Session not sealed");
             }
-            Objects.requireNonNull(mPackageName);
-            Objects.requireNonNull(mSigningDetails);
-            Objects.requireNonNull(mResolvedBaseFile);
+            if (mPackageName == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Session no package name");
+            }
+            if (mSigningDetails == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Session no signing data");
+            }
+            if (mResolvedBaseFile == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Session no resolved base file");
+            }
             final PackageLite result;
             if (!isApexSession()) {
                 // For mode inherit existing, it would link/copy existing files to stage dir in
@@ -3176,7 +3294,7 @@
             }
         }
 
-        final List<File> addedFiles = getAddedApksLocked();
+        final List<ApkLite> addedFiles = getAddedApkLitesLocked();
         if (addedFiles.isEmpty()
                 && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -3190,15 +3308,7 @@
         final ArraySet<String> requiredSplitTypes = new ArraySet<>();
         final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>();
         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
-        for (File addedFile : addedFiles) {
-            final ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
-                    addedFile, ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
-            if (result.isError()) {
-                throw new PackageManagerException(result.getErrorCode(),
-                        result.getErrorMessage(), result.getException());
-            }
-
-            final ApkLite apk = result.getResult();
+        for (ApkLite apk : addedFiles) {
             if (!stagedSplits.add(apk.getSplitName())) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Split " + apk.getSplitName() + " was defined multiple times");
@@ -3214,7 +3324,7 @@
             }
             mHasDeviceAdminReceiver = apk.isHasDeviceAdminReceiver();
 
-            assertApkConsistentLocked(String.valueOf(addedFile), apk);
+            assertApkConsistentLocked(String.valueOf(apk), apk);
 
             // Take this opportunity to enforce uniform naming
             final String targetName = ApkLiteParseUtils.splitNameToFileName(apk);
@@ -3235,7 +3345,10 @@
             }
 
             final File targetFile = new File(stageDir, targetName);
-            resolveAndStageFileLocked(addedFile, targetFile, apk.getSplitName());
+            if (!isArchivedInstallation()) {
+                final File sourceFile = new File(apk.getPath());
+                resolveAndStageFileLocked(sourceFile, targetFile, apk.getSplitName());
+            }
 
             // Base is coming from session
             if (apk.getSplitName() == null) {
@@ -3275,6 +3388,23 @@
             }
         }
 
+        if (isArchivedInstallation()) {
+            if (!isArchivedInstallationAllowed(mPackageName)) {
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_SESSION_INVALID,
+                        "Archived installation of this package is not allowed.");
+            }
+
+            if (!isInstalledByAdb(getInstallSource().mInitiatingPackageName)
+                    && !mPm.mArchiverService.verifySupportsUnarchival(
+                    getInstallSource().mInstallerPackageName)) {
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_SESSION_INVALID,
+                        "Installer has to support unarchival in order to install archived "
+                                + "packages.");
+            }
+        }
+
         if (isIncrementalInstallation()) {
             if (!isIncrementalInstallationAllowed(mPackageName)) {
                 throw new PackageManagerException(
@@ -4005,6 +4135,11 @@
             NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
         }
 
+        // Skip native libraries processing for archival installation.
+        if (isArchivedInstallation()) {
+            return;
+        }
+
         NativeLibraryHelper.Handle handle = null;
         try {
             handle = NativeLibraryHelper.Handle.create(packageLite);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7ccf713..0c2f1ca 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -36,7 +36,6 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
-
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
 import static com.android.server.pm.DexOptHelper.useArtService;
@@ -77,6 +76,7 @@
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.ChangedPackages;
 import android.content.pm.Checksum;
@@ -115,7 +115,11 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VersionedPackage;
 import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.parsing.ApkLite;
+import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
@@ -796,6 +800,8 @@
 
     final PackageInstallerService mInstallerService;
 
+    final PackageArchiverService mArchiverService;
+
     final ArtManagerService mArtManagerService;
 
     // TODO(b/260124949): Remove these.
@@ -1624,7 +1630,8 @@
                 (i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(),
                         i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(),
                         context),
-                (i, pm) -> new UpdateOwnershipHelper());
+                (i, pm) -> new UpdateOwnershipHelper(),
+                (i, pm) -> new PackageArchiverService(i.getContext(), pm));
 
         if (Build.VERSION.SDK_INT <= 0) {
             Slog.w(TAG, "**** ro.build.version.sdk not set!");
@@ -1769,6 +1776,7 @@
         mFactoryTest = testParams.factoryTest;
         mIncrementalManager = testParams.incrementalManager;
         mInstallerService = testParams.installerService;
+        mArchiverService = testParams.archiverService;
         mInstantAppRegistry = testParams.instantAppRegistry;
         mChangedPackagesTracker = testParams.changedPackagesTracker;
         mInstantAppResolverConnection = testParams.instantAppResolverConnection;
@@ -1967,9 +1975,6 @@
         mApexManager = injector.getApexManager();
         mAppsFilter = mInjector.getAppsFilter();
 
-        mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
-                mInjector.getUserManagerInternal(), new DeletePackageHelper(this));
-
         mChangedPackagesTracker = new ChangedPackagesTracker();
 
         mAppInstallDir = new File(Environment.getDataDirectory(), "app");
@@ -1983,8 +1988,11 @@
         mAppDataHelper = new AppDataHelper(this);
         mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
         mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
-        mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
-                mAppDataHelper);
+        mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper);
+
+        mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
+                mInjector.getUserManagerInternal(), mDeletePackageHelper);
+
         mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
         mPreferredActivityHelper = new PreferredActivityHelper(this);
         mResolveIntentHelper = new ResolveIntentHelper(mContext, mPreferredActivityHelper,
@@ -2348,6 +2356,7 @@
             });
 
             mInstallerService = mInjector.getPackageInstallerService();
+            mArchiverService = mInjector.getPackageArchiverService();
             final ComponentName instantAppResolverComponent = getInstantAppResolver(computer);
             if (instantAppResolverComponent != null) {
                 if (DEBUG_INSTANT) {
@@ -4289,16 +4298,17 @@
     }
 
     public PackageFreezer freezePackage(String packageName, int userId, String killReason,
-            int exitInfoReason) {
-        return new PackageFreezer(packageName, userId, killReason, this, exitInfoReason);
+            int exitInfoReason, InstallRequest request) {
+        return new PackageFreezer(packageName, userId, killReason, this, exitInfoReason, request);
     }
 
     public PackageFreezer freezePackageForDelete(String packageName, int userId, int deleteFlags,
             String killReason, int exitInfoReason) {
         if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) {
-            return new PackageFreezer(this);
+            return new PackageFreezer(this, null /* request */);
         } else {
-            return freezePackage(packageName, userId, killReason, exitInfoReason);
+            return freezePackage(packageName, userId, killReason, exitInfoReason,
+                    null /* request */);
         }
     }
 
@@ -4608,7 +4618,7 @@
                     mDomainVerificationConnection, mInstallerService, mPackageProperty,
                     mResolveComponentName, mInstantAppResolverSettingsComponent,
                     mRequiredSdkSandboxPackage, mServicesExtensionPackageName,
-                    mSharedSystemSharedLibraryPackageName);
+                    mSharedSystemSharedLibraryPackageName, mArchiverService);
         }
 
         @Override
@@ -4627,7 +4637,7 @@
             try (PackageFreezer ignored =
                             freezePackage(packageName, UserHandle.USER_ALL,
                                     "clearApplicationProfileData",
-                                    ApplicationExitInfo.REASON_OTHER)) {
+                                    ApplicationExitInfo.REASON_OTHER, null /* request */)) {
                 synchronized (mInstallLock) {
                     mAppDataHelper.clearAppProfilesLIF(pkg);
                 }
@@ -4670,7 +4680,7 @@
                     final boolean succeeded;
                     try (PackageFreezer freezer = freezePackage(packageName, UserHandle.USER_ALL,
                             "clearApplicationUserData",
-                            ApplicationExitInfo.REASON_USER_REQUESTED)) {
+                            ApplicationExitInfo.REASON_USER_REQUESTED, null /* request */)) {
                         synchronized (mInstallLock) {
                             succeeded = clearApplicationUserDataLIF(snapshotComputer(), packageName,
                                     userId);
@@ -6292,6 +6302,37 @@
             }
         }
 
+        @Override
+        public ArchivedPackageParcel getArchivedPackage(String apkPath) {
+            ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
+                    new File(apkPath), ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
+            if (result.isError()) {
+                throw new IllegalArgumentException(result.getErrorMessage(), result.getException());
+            }
+            final ApkLite apk = result.getResult();
+
+            ArchivedPackageParcel archPkg = new ArchivedPackageParcel();
+            archPkg.packageName = apk.getPackageName();
+            archPkg.signingDetails = apk.getSigningDetails();
+
+            archPkg.versionCodeMajor = apk.getVersionCodeMajor();
+            archPkg.versionCode = apk.getVersionCode();
+
+            archPkg.targetSdkVersion = apk.getTargetSdkVersion();
+
+            // These get translated in flags important for user data management.
+            archPkg.backupAllowed = apk.isBackupAllowed();
+            archPkg.defaultToDeviceProtectedStorage =
+                    apk.isDefaultToDeviceProtectedStorage();
+            archPkg.requestLegacyExternalStorage = apk.isRequestLegacyExternalStorage();
+            archPkg.userDataFragile = apk.isUserDataFragile();
+            archPkg.clearUserDataOnFailedRestoreAllowed =
+                    apk.isClearUserDataOnFailedRestoreAllowed();
+
+            return archPkg;
+        }
+
         /**
          * Wait for the handler to finish handling all pending messages.
          * @param timeoutMillis Maximum time in milliseconds to wait.
@@ -6933,6 +6974,11 @@
             return mDistractingPackageHelper.getDistractingPackageRestrictionsAsUser(snapshot,
                     packageNames, userId, callingUid);
         }
+
+        @Override
+        public ParceledListSlice<PackageInstaller.SessionInfo> getHistoricalSessions(int userId) {
+            return mInstallerService.getHistoricalSessions(userId);
+        }
     }
 
     private void setEnabledOverlayPackages(@UserIdInt int userId,
@@ -7748,7 +7794,6 @@
 
             consumer.accept(mPackageStateMutator);
             mPackageStateMutator.onFinished();
-            onChanged();
         }
 
         return PackageStateMutator.Result.SUCCESS;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
index 51840e7..9495279 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java
@@ -127,6 +127,8 @@
             mPreparingPackageParserProducer;
     private final Singleton<PackageInstallerService>
             mPackageInstallerServiceProducer;
+    private final Singleton<PackageArchiverService>
+            mPackageArchiverServiceProducer;
     private final ProducerWithArgument<InstantAppResolverConnection, ComponentName>
             mInstantAppResolverConnectionProducer;
     private final Singleton<LegacyPermissionManagerInternal>
@@ -185,7 +187,8 @@
             Producer<IBackupManager> iBackupManager,
             Producer<SharedLibrariesImpl> sharedLibrariesProducer,
             Producer<CrossProfileIntentFilterHelper> crossProfileIntentFilterHelperProducer,
-            Producer<UpdateOwnershipHelper> updateOwnershipHelperProducer) {
+            Producer<UpdateOwnershipHelper> updateOwnershipHelperProducer,
+            Producer<PackageArchiverService> packageArchiverServiceProducer) {
         mContext = context;
         mLock = lock;
         mInstaller = installer;
@@ -241,6 +244,7 @@
         mCrossProfileIntentFilterHelperProducer = new Singleton<>(
                 crossProfileIntentFilterHelperProducer);
         mUpdateOwnershipHelperProducer = new Singleton<>(updateOwnershipHelperProducer);
+        mPackageArchiverServiceProducer = new Singleton<>(packageArchiverServiceProducer);
     }
 
     /**
@@ -387,6 +391,10 @@
         return mPackageInstallerServiceProducer.get(this, mPackageManager);
     }
 
+    public PackageArchiverService getPackageArchiverService() {
+        return mPackageArchiverServiceProducer.get(this, mPackageManager);
+    }
+
     public InstantAppResolverConnection getInstantAppResolverConnection(
             ComponentName instantAppResolverComponent) {
         return mInstantAppResolverConnectionProducer.produce(
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index ca57209..b91ce4b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -60,6 +60,7 @@
     public @Nullable String incidentReportApproverPackage;
     public IncrementalManager incrementalManager;
     public PackageInstallerService installerService;
+    public PackageArchiverService archiverService;
     public InstantAppRegistry instantAppRegistry;
     public ChangedPackagesTracker changedPackagesTracker = new ChangedPackagesTracker();
     public InstantAppResolverConnection instantAppResolverConnection;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index db997d8..2028231 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -919,16 +919,22 @@
 
         final File packageFile = new File(packagePath);
         final long sizeBytes;
-        try {
-            sizeBytes = InstallLocationUtils.calculateInstalledSize(pkg, abiOverride);
-        } catch (IOException e) {
-            if (!packageFile.exists()) {
-                ret.recommendedInstallLocation = InstallLocationUtils.RECOMMEND_FAILED_INVALID_URI;
-            } else {
-                ret.recommendedInstallLocation = InstallLocationUtils.RECOMMEND_FAILED_INVALID_APK;
-            }
+        if (!PackageInstallerSession.isArchivedInstallation(flags)) {
+            try {
+                sizeBytes = InstallLocationUtils.calculateInstalledSize(pkg, abiOverride);
+            } catch (IOException e) {
+                if (!packageFile.exists()) {
+                    ret.recommendedInstallLocation =
+                            InstallLocationUtils.RECOMMEND_FAILED_INVALID_URI;
+                } else {
+                    ret.recommendedInstallLocation =
+                            InstallLocationUtils.RECOMMEND_FAILED_INVALID_APK;
+                }
 
-            return ret;
+                return ret;
+            }
+        } else {
+            sizeBytes = 0;
         }
 
         final PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 8bdbe04..d9f1df5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -43,6 +43,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstaller;
@@ -82,6 +83,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
@@ -105,6 +107,7 @@
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.IntArray;
+import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -246,6 +249,8 @@
                     return runStreamingInstall();
                 case "install-incremental":
                     return runIncrementalInstall();
+                case "install-archived":
+                    return runArchivedInstall();
                 case "install-abandon":
                 case "install-destroy":
                     return runInstallAbandon();
@@ -1549,6 +1554,16 @@
         return doRunInstall(params);
     }
 
+    private int runArchivedInstall() throws RemoteException {
+        final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
+        params.sessionParams.installFlags |= PackageManager.INSTALL_ARCHIVED;
+        if (params.sessionParams.dataLoaderParams == null) {
+            params.sessionParams.setDataLoaderParams(
+                    PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
+        }
+        return doRunInstall(params);
+    }
+
     private int runIncrementalInstall() throws RemoteException {
         final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
         if (params.sessionParams.dataLoaderParams == null) {
@@ -1565,9 +1580,22 @@
     private int doRunInstall(final InstallParams params) throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
 
+        int requestUserId = params.userId;
+        if (requestUserId != UserHandle.USER_ALL && requestUserId != UserHandle.USER_CURRENT) {
+            UserManagerInternal umi =
+                    LocalServices.getService(UserManagerInternal.class);
+            UserInfo userInfo = umi.getUserInfo(requestUserId);
+            if (userInfo == null) {
+                pw.println("Failure [user " + requestUserId + " doesn't exist]");
+                return 1;
+            }
+        }
+
         final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
         final boolean isApex =
                 (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+        final boolean installArchived =
+                (params.sessionParams.installFlags & PackageManager.INSTALL_ARCHIVED) != 0;
 
         ArrayList<String> args = getRemainingArgs();
 
@@ -1584,6 +1612,13 @@
             return 1;
         }
 
+        if (installArchived) {
+            if (hasSplits) {
+                pw.println("Error: can't have SPLIT(s) for Archival install");
+                return 1;
+            }
+        }
+
         if (!isStreaming) {
             if (fromStdIn && hasSplits) {
                 pw.println("Error: can't specify SPLIT(s) along with STDIN");
@@ -1602,8 +1637,8 @@
         boolean abandonSession = true;
         try {
             if (isStreaming) {
-                if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex)
-                        != PackageInstaller.STATUS_SUCCESS) {
+                if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex,
+                        installArchived) != PackageInstaller.STATUS_SUCCESS) {
                     return 1;
                 }
             } else {
@@ -2319,6 +2354,15 @@
                     break;
                 case "--user":
                     userId = UserHandle.parseUserArg(getNextArgRequired());
+                    if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT) {
+                        UserManagerInternal umi =
+                                LocalServices.getService(UserManagerInternal.class);
+                        UserInfo userInfo = umi.getUserInfo(userId);
+                        if (userInfo == null) {
+                            pw.println("Failure [user " + userId + " doesn't exist]");
+                            return 1;
+                        }
+                    }
                     break;
                 case "--versionCode":
                     versionCode = Long.parseLong(getNextArgRequired());
@@ -3836,7 +3880,7 @@
     }
 
     private int doAddFiles(int sessionId, ArrayList<String> args, long sessionSizeBytes,
-            boolean isApex) throws RemoteException {
+            boolean isApex, boolean installArchived) throws RemoteException {
         PackageInstaller.Session session = null;
         try {
             session = new PackageInstaller.Session(
@@ -3845,9 +3889,17 @@
             // 1. Single file from stdin.
             if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
                 final String name = "base" + RANDOM.nextInt() + "." + (isApex ? "apex" : "apk");
-                final Metadata metadata = Metadata.forStdIn(name);
-                session.addFile(LOCATION_DATA_APP, name, sessionSizeBytes,
-                        metadata.toByteArray(), null);
+                final long size;
+                final Metadata metadata;
+                if (!installArchived) {
+                    metadata = Metadata.forStdIn(name);
+                    size = sessionSizeBytes;
+                } else {
+                    metadata = Metadata.forArchived(
+                            getArchivedPackage(STDIN_PATH, sessionSizeBytes));
+                    size = -1;
+                }
+                session.addFile(LOCATION_DATA_APP, name, size, metadata.toByteArray(), null);
                 return 0;
             }
 
@@ -3856,16 +3908,21 @@
 
                 if (delimLocation != -1) {
                     // 2. File with specified size read from stdin.
+                    if (installArchived) {
+                        getOutPrintWriter().println(
+                                "Error: can't install with size from STDIN for Archival install");
+                        return 1;
+                    }
                     if (processArgForStdin(arg, session) != 0) {
                         return 1;
                     }
                 } else {
                     // 3. Local file.
-                    processArgForLocalFile(arg, session);
+                    processArgForLocalFile(arg, session, installArchived);
                 }
             }
             return 0;
-        } catch (IllegalArgumentException e) {
+        } catch (IOException | IllegalArgumentException e) {
             getErrPrintWriter().println("Failed to add file(s), reason: " + e);
             getOutPrintWriter().println("Failure [failed to add file(s)]");
             return 1;
@@ -3954,26 +4011,67 @@
         }
     }
 
-    private void processArgForLocalFile(String arg, PackageInstaller.Session session) {
+    private ArchivedPackageParcel getArchivedPackage(String inPath, long sizeBytes)
+            throws RemoteException, IOException {
+        final var fdWithSize = openInFile(inPath, sizeBytes);
+        if (fdWithSize.first == null) {
+            throw new IllegalArgumentException("Error: Can't open file: " + inPath);
+        }
+
+        File tmpFile = null;
+        final ParcelFileDescriptor fd = fdWithSize.first;
+        try (InputStream inStream = new AutoCloseInputStream(fd)) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                File tmpStagingDir = Environment.getDataAppDirectory(null);
+                tmpFile = new File(tmpStagingDir, "tmdl" + RANDOM.nextInt() + ".tmp");
+
+                try (OutputStream outStream = new FileOutputStream(tmpFile)) {
+                    Streams.copy(inStream, outStream);
+                }
+
+                return mInterface.getArchivedPackage(tmpFile.getAbsolutePath());
+            } finally {
+                if (tmpFile != null) {
+                    tmpFile.delete();
+                }
+                Binder.restoreCallingIdentity(identity);
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Error: Can't stage file: " + inPath, e);
+        }
+    }
+
+    private void processArgForLocalFile(String arg, PackageInstaller.Session session,
+            boolean installArchived) throws IOException, RemoteException {
         final String inPath = arg;
 
         final File file = new File(inPath);
         final String name = file.getName();
-        final long size = getFileStatSize(file);
-        final Metadata metadata = Metadata.forLocalFile(inPath);
+        final long size;
+        final Metadata metadata;
+        if (installArchived) {
+            metadata = Metadata.forArchived(getArchivedPackage(inPath, -1));
+            size = 0;
+        } else {
+            metadata = Metadata.forLocalFile(inPath);
+            size = getFileStatSize(file);
+        }
 
         byte[] v4signatureBytes = null;
-        // Try to load the v4 signature file for the APK; it might not exist.
-        final String v4SignaturePath = inPath + V4Signature.EXT;
-        final ParcelFileDescriptor pfd = openFileForSystem(v4SignaturePath, "r");
-        if (pfd != null) {
-            try {
-                final V4Signature v4signature = V4Signature.readFrom(pfd);
-                v4signatureBytes = v4signature.toByteArray();
-            } catch (IOException ex) {
-                Slog.e(TAG, "V4 signature file exists but failed to be parsed.", ex);
-            } finally {
-                IoUtils.closeQuietly(pfd);
+        if (!installArchived) {
+            // Try to load the v4 signature file for the APK; it might not exist.
+            final String v4SignaturePath = inPath + V4Signature.EXT;
+            final ParcelFileDescriptor pfd = openFileForSystem(v4SignaturePath, "r");
+            if (pfd != null) {
+                try {
+                    final V4Signature v4signature = V4Signature.readFrom(pfd);
+                    v4signatureBytes = v4signature.toByteArray();
+                } catch (IOException ex) {
+                    Slog.e(TAG, "V4 signature file exists but failed to be parsed.", ex);
+                } finally {
+                    IoUtils.closeQuietly(pfd);
+                }
             }
         }
 
@@ -3995,6 +4093,32 @@
         return 0;
     }
 
+    private Pair<ParcelFileDescriptor, Long> openInFile(String inPath, long sizeBytes)
+            throws IOException {
+        final ParcelFileDescriptor fd;
+        if (STDIN_PATH.equals(inPath)) {
+            fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+        } else if (inPath != null) {
+            fd = openFileForSystem(inPath, "r");
+            if (fd == null) {
+                return Pair.create(null, -1L);
+            }
+            sizeBytes = fd.getStatSize();
+            if (sizeBytes < 0) {
+                fd.close();
+                getErrPrintWriter().println("Unable to get size of: " + inPath);
+                return Pair.create(null, -1L);
+            }
+        } else {
+            fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+        }
+        if (sizeBytes <= 0) {
+            getErrPrintWriter().println("Error: must specify an APK size");
+            return Pair.create(null, 1L);
+        }
+        return Pair.create(fd, sizeBytes);
+    }
+
     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
             boolean logSuccess) throws RemoteException {
         PackageInstaller.Session session = null;
@@ -4004,26 +4128,13 @@
 
             final PrintWriter pw = getOutPrintWriter();
 
-            final ParcelFileDescriptor fd;
-            if (STDIN_PATH.equals(inPath)) {
-                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
-            } else if (inPath != null) {
-                fd = openFileForSystem(inPath, "r");
-                if (fd == null) {
-                    return -1;
-                }
-                sizeBytes = fd.getStatSize();
-                if (sizeBytes < 0) {
-                    getErrPrintWriter().println("Unable to get size of: " + inPath);
-                    return -1;
-                }
-            } else {
-                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+            final var fdWithSize = openInFile(inPath, sizeBytes);
+            if (fdWithSize.first == null) {
+                long resultCode = fdWithSize.second;
+                return (int) resultCode;
             }
-            if (sizeBytes <= 0) {
-                getErrPrintWriter().println("Error: must specify an APK size");
-                return 1;
-            }
+            final ParcelFileDescriptor fd = fdWithSize.first;
+            sizeBytes = fdWithSize.second;
 
             session.write(splitName, 0, sizeBytes, fd);
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index a1e5153..fbe5a51 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -18,9 +18,11 @@
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.DataLoaderParams;
 import android.content.pm.InstallationFile;
 import android.content.pm.PackageInstaller;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.ShellCommand;
 import android.service.dataloader.DataLoaderService;
@@ -37,6 +39,7 @@
 import java.nio.ByteOrder;
 import java.nio.charset.StandardCharsets;
 import java.security.SecureRandom;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -136,9 +139,13 @@
          * Everything streamed.
          */
         static final byte STREAMING = 3;
+        /**
+         * Archived install.
+         */
+        static final byte ARCHIVED = 4;
 
         private final byte mMode;
-        private final String mData;
+        private final byte[] mData;
         private final String mSalt;
 
         private static AtomicLong sGlobalSalt = new AtomicLong((new SecureRandom()).nextLong());
@@ -156,6 +163,21 @@
             return new Metadata(LOCAL_FILE, filePath, nextGlobalSalt().toString());
         }
 
+        /** @hide */
+        @VisibleForTesting
+        public static Metadata forArchived(ArchivedPackageParcel archivedPackage) {
+            Parcel parcel = Parcel.obtain();
+            byte[] bytes;
+            try {
+                parcel.writeParcelable(archivedPackage, 0);
+                bytes = parcel.marshall();
+            } finally {
+                parcel.recycle();
+            }
+
+            return new Metadata(ARCHIVED, bytes, null);
+        }
+
         static Metadata forDataOnlyStreaming(String fileId) {
             return new Metadata(DATA_ONLY_STREAMING, fileId);
         }
@@ -169,8 +191,12 @@
         }
 
         private Metadata(byte mode, String data, String salt) {
+            this(mode, (data != null ? data : "").getBytes(StandardCharsets.UTF_8), salt);
+        }
+
+        private Metadata(byte mode, byte[] data, String salt) {
             this.mMode = mode;
-            this.mData = (data == null) ? "" : data;
+            this.mData = data;
             this.mSalt = salt;
         }
 
@@ -181,22 +207,21 @@
             int offset = 0;
             final byte mode = bytes[offset];
             offset += 1;
-            final String data;
+            final byte[] data;
             final String salt;
             switch (mode) {
                 case LOCAL_FILE: {
                     int dataSize = ByteBuffer.wrap(bytes, offset, 4).order(
                             ByteOrder.LITTLE_ENDIAN).getInt();
                     offset += 4;
-                    data = new String(bytes, offset, dataSize, StandardCharsets.UTF_8);
+                    data = Arrays.copyOfRange(bytes, offset, offset + dataSize);
                     offset += dataSize;
                     salt = new String(bytes, offset, bytes.length - offset,
                             StandardCharsets.UTF_8);
                     break;
                 }
                 default:
-                    data = new String(bytes, offset, bytes.length - offset,
-                            StandardCharsets.UTF_8);
+                    data = Arrays.copyOfRange(bytes, offset, bytes.length);
                     salt = null;
                     break;
             }
@@ -207,7 +232,7 @@
         @VisibleForTesting
         public byte[] toByteArray() {
             final byte[] result;
-            final byte[] dataBytes = this.mData.getBytes(StandardCharsets.UTF_8);
+            final byte[] dataBytes = this.mData;
             switch (this.mMode) {
                 case LOCAL_FILE: {
                     int dataSize = dataBytes.length;
@@ -237,9 +262,26 @@
             return this.mMode;
         }
 
-        String getData() {
+        byte[] getData() {
             return this.mData;
         }
+
+        ArchivedPackageParcel getArchivedPackage() {
+            if (getMode() != ARCHIVED) {
+                throw new IllegalStateException("Not an archived package metadata.");
+            }
+
+            Parcel parcel = Parcel.obtain();
+            ArchivedPackageParcel result;
+            try {
+                parcel.unmarshall(this.mData, 0, this.mData.length);
+                parcel.setDataPosition(0);
+                result = parcel.readParcelable(ArchivedPackageParcel.class.getClassLoader());
+            } finally {
+                parcel.recycle();
+            }
+            return result;
+        }
     }
 
     private static class DataLoader implements DataLoaderService.DataLoader {
@@ -278,7 +320,9 @@
                         case Metadata.LOCAL_FILE: {
                             ParcelFileDescriptor incomingFd = null;
                             try {
-                                incomingFd = getLocalFilePFD(shellCommand, metadata.getData());
+                                final String filePath = new String(metadata.getData(),
+                                        StandardCharsets.UTF_8);
+                                incomingFd = getLocalFilePFD(shellCommand, filePath);
                                 mConnector.writeData(file.getName(), 0, incomingFd.getStatSize(),
                                         incomingFd);
                             } finally {
@@ -286,6 +330,10 @@
                             }
                             break;
                         }
+                        case Metadata.ARCHIVED: {
+                            // Do nothing, metadata already contains everything needed for install.
+                            break;
+                        }
                         default:
                             Slog.e(TAG, "Unsupported metadata mode: " + metadata.getMode());
                             return false;
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 2d58fe5..7ad336c 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -51,13 +51,15 @@
     public static final int STEP_RECONCILE = 3;
     public static final int STEP_COMMIT = 4;
     public static final int STEP_DEXOPT = 5;
+    public static final int STEP_FREEZE_INSTALL = 6;
 
     @IntDef(prefix = {"STEP_"}, value = {
             STEP_PREPARE,
             STEP_SCAN,
             STEP_RECONCILE,
             STEP_COMMIT,
-            STEP_DEXOPT
+            STEP_DEXOPT,
+            STEP_FREEZE_INSTALL
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface StepInt {
@@ -109,10 +111,17 @@
 
         long versionCode = 0, apksSize = 0;
         if (success) {
-            final PackageSetting ps = mInstallRequest.getScannedPackageSetting();
-            if (ps != null) {
-                versionCode = ps.getVersionCode();
-                apksSize = getApksSize(ps.getPath());
+            // TODO: Remove temp try-catch to avoid IllegalStateException. The reason is because
+            //  the scan result is null for installExistingPackageAsUser(). Because it's installing
+            //  a package that's already existing, there's no scanning or parsing involved
+            try {
+                final PackageSetting ps = mInstallRequest.getScannedPackageSetting();
+                if (ps != null) {
+                    versionCode = ps.getVersionCode();
+                    apksSize = getApksSize(ps.getPath());
+                }
+            } catch (IllegalStateException | NullPointerException e) {
+                // no-op
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index c762fd3..5f44528 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -164,8 +164,7 @@
         }
     }
 
-    public void populateUsers(int[] userIds, PackageSetting deletedPackageSetting) {
-        mRemovedUsers = userIds;
+    public void populateBroadcastUsers(PackageSetting deletedPackageSetting) {
         if (mRemovedUsers == null) {
             mBroadcastUsers = null;
             return;
@@ -173,8 +172,8 @@
 
         mBroadcastUsers = EMPTY_INT_ARRAY;
         mInstantUserIds = EMPTY_INT_ARRAY;
-        for (int i = userIds.length - 1; i >= 0; --i) {
-            final int userId = userIds[i];
+        for (int i = mRemovedUsers.length - 1; i >= 0; --i) {
+            final int userId = mRemovedUsers[i];
             if (deletedPackageSetting.getInstantApp(userId)) {
                 mInstantUserIds = ArrayUtils.appendInt(mInstantUserIds, userId);
             } else {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7cac3e1..88184c0 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -818,7 +818,7 @@
             if (userState.isInstalled()) {
                 return true;
             }
-            if (userState.getCeDataInode() > 0) {
+            if (userState.dataExists()) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PrepareFailure.java b/services/core/java/com/android/server/pm/PrepareFailure.java
index 3180bac..09cb6b9 100644
--- a/services/core/java/com/android/server/pm/PrepareFailure.java
+++ b/services/core/java/com/android/server/pm/PrepareFailure.java
@@ -42,7 +42,8 @@
     }
 
     PrepareFailure(String message, Exception e) {
-        super(((PackageManagerException) e).error,
+        super(e instanceof PackageManagerException ? ((PackageManagerException) e).error
+                        : PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                 ExceptionUtils.getCompleteMessage(message, e));
     }
 
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 6d3b26c..2aedf0d 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -253,17 +253,66 @@
         }
     }
 
-    public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles,
-            PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
+    public void clearPackageStateForUserLIF(PackageSetting ps, int userId,
+            PackageRemovedInfo outInfo, int flags) {
+        final AndroidPackage pkg;
+        final SharedUserSetting sus;
+        synchronized (mPm.mLock) {
+            pkg = mPm.mPackages.get(ps.getPackageName());
+            sus = mPm.mSettings.getSharedUserSettingLPr(ps);
+        }
+
+        mAppDataHelper.destroyAppProfilesLIF(pkg);
+
+        final List<AndroidPackage> sharedUserPkgs =
+                sus != null ? sus.getPackages() : Collections.emptyList();
+        final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm);
+        final int[] userIds = (userId == UserHandle.USER_ALL) ? mUserManagerInternal.getUserIds()
+                : new int[] {userId};
+        for (int nextUserId : userIds) {
+            if (DEBUG_REMOVE) {
+                Slog.d(TAG, "Updating package:" + ps.getPackageName() + " install state for user:"
+                        + nextUserId);
+            }
+            if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+                mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
+                        FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+                ps.setCeDataInode(-1, nextUserId);
+            }
+            mAppDataHelper.clearKeystoreData(nextUserId, ps.getAppId());
+            preferredActivityHelper.clearPackagePreferredActivities(ps.getPackageName(),
+                    nextUserId);
+            mPm.mDomainVerificationManager.clearPackageForUser(ps.getPackageName(), nextUserId);
+        }
+        mPermissionManager.onPackageUninstalled(ps.getPackageName(), ps.getAppId(), ps, pkg,
+                sharedUserPkgs, userId);
+
+        if (outInfo != null) {
+            if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+                outInfo.mDataRemoved = true;
+            }
+            outInfo.mRemovedPackage = ps.getPackageName();
+            outInfo.mInstallerPackageName = ps.getInstallSource().mInstallerPackageName;
+            outInfo.mIsStaticSharedLib = pkg != null && pkg.getStaticSharedLibraryName() != null;
+            outInfo.mRemovedAppId = ps.getAppId();
+            outInfo.mBroadcastUsers = outInfo.mRemovedUsers;
+            outInfo.mIsExternal = ps.isExternalStorage();
+            outInfo.mRemovedPackageVersionCode = ps.getVersionCode();
+        }
+    }
+
+    // Called to clean up disabled system packages
+    public void removePackageData(final PackageSetting deletedPs, @NonNull int[] allUserHandles) {
         synchronized (mPm.mInstallLock) {
-            removePackageDataLIF(deletedPs, allUserHandles, outInfo, flags, writeSettings);
+            removePackageDataLIF(deletedPs, allUserHandles, /* outInfo= */ null,
+                    /* flags= */ 0, /* writeSettings= */ false);
         }
     }
 
     /*
      * This method deletes the package from internal data structures. If the DELETE_KEEP_DATA
      * flag is not set, the data directory is removed as well.
-     * make sure this flag is set for partially installed apps. If not its meaningless to
+     * make sure this flag is set for partially installed apps. If not it's meaningless to
      * delete a partially installed application.
      */
     @GuardedBy("mPm.mInstallLock")
@@ -278,8 +327,7 @@
             outInfo.mInstallerPackageName = deletedPs.getInstallSource().mInstallerPackageName;
             outInfo.mIsStaticSharedLib = deletedPkg != null
                     && deletedPkg.getStaticSharedLibraryName() != null;
-            outInfo.populateUsers(deletedPs.queryInstalledUsers(
-                    mUserManagerInternal.getUserIds(), true), deletedPs);
+            outInfo.populateBroadcastUsers(deletedPs);
             outInfo.mIsExternal = deletedPs.isExternalStorage();
             outInfo.mRemovedPackageVersionCode = deletedPs.getVersionCode();
         }
@@ -314,7 +362,6 @@
         int removedAppId = -1;
 
         // writer
-        boolean installedStateChanged = false;
         if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
             final SparseBooleanArray changedUsers = new SparseBooleanArray();
             synchronized (mPm.mLock) {
@@ -354,9 +401,10 @@
                 mPm.postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
             }
         }
-        // make sure to preserve per-user disabled state if this removal was just
+        // make sure to preserve per-user installed state if this removal was just
         // a downgrade of a system app to the factory package
-        if (outInfo != null && outInfo.mOrigUsers != null) {
+        boolean installedStateChanged = false;
+        if (outInfo != null && outInfo.mOrigUsers != null && deletedPs.isSystem()) {
             if (DEBUG_REMOVE) {
                 Slog.d(TAG, "Propagating install state across downgrade");
             }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 307867c..1137681 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -27,7 +27,6 @@
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
-
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 import static com.android.server.pm.PackageManagerService.WRITE_USER_PACKAGE_RESTRICTIONS;
 import static com.android.server.pm.SharedUidMigration.BEST_EFFORT;
@@ -2065,8 +2064,10 @@
                         ATTR_ARCHIVE_ACTIVITY_TITLE);
                 Path iconPath = Path.of(parser.getAttributeValue(null,
                         ATTR_ARCHIVE_ICON_PATH));
-                Path monochromeIconPath = Path.of(parser.getAttributeValue(null,
-                        ATTR_ARCHIVE_MONOCHROME_ICON_PATH));
+                String monochromeAttribute = parser.getAttributeValue(null,
+                        ATTR_ARCHIVE_MONOCHROME_ICON_PATH);
+                Path monochromeIconPath = monochromeAttribute == null ? null : Path.of(
+                        monochromeAttribute);
 
                 if (title == null || iconPath == null) {
                     Slog.wtf(TAG,
@@ -2916,11 +2917,7 @@
 
             StringBuilder sb = new StringBuilder();
             for (final PackageSetting ps : mPackages.values()) {
-                // TODO(b/135203078): This doesn't handle multiple users
-                final String dataPath = PackageInfoUtils.getDataDir(ps, UserHandle.USER_SYSTEM)
-                        .getAbsolutePath();
-
-                if (ps.getPkg() == null || dataPath == null) {
+                if (ps.getPkg() == null) {
                     if (!"android".equals(ps.getPackageName())) {
                         Slog.w(TAG, "Skipping " + ps + " due to missing metadata");
                     }
@@ -2932,6 +2929,10 @@
                     continue;
                 }
 
+                // TODO(b/135203078): This doesn't handle multiple users
+                final File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.USER_SYSTEM);
+                final String dataPath = dataDir == null ? "null" : dataDir.getAbsolutePath();
+
                 final boolean isDebug = ps.getPkg().isDebuggable();
                 final IntArray gids = new IntArray();
                 for (final int userId : userIds) {
@@ -2973,7 +2974,7 @@
                 sb.append(ps.getSeInfo());
                 sb.append(" ");
                 final int gidsSize = gids.size();
-                if (gids != null && gids.size() > 0) {
+                if (gids.size() > 0) {
                     sb.append(gids.get(0));
                     for (int i = 1; i < gidsSize; i++) {
                         sb.append(",");
@@ -4746,6 +4747,7 @@
             ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
             ApplicationInfo.PRIVATE_FLAG_ODM, "ODM",
             ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING, "PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING",
+            ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA, "PRIVATE_FLAG_HAS_FRAGILE_USER_DATA",
     };
 
     void dumpVersionLPr(IndentingPrintWriter pw) {
@@ -4893,8 +4895,6 @@
             pw.print("]");
         }
         pw.println();
-        File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
-        pw.print(prefix); pw.print("  dataDir="); pw.println(dataDir.getAbsolutePath());
         if (pkg != null) {
             pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
             pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
@@ -5195,6 +5195,10 @@
             pw.print("      installReason=");
             pw.println(userState.getInstallReason());
 
+            File dataDir = PackageInfoUtils.getDataDir(ps, user.id);
+            pw.print("      dataDir=");
+            pw.println(dataDir.getAbsolutePath());
+
             final PackageUserStateInternal pus = ps.readUserState(user.id);
             pw.print("      firstInstallTime=");
             date.setTime(pus.getFirstInstallTimeMillis());
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index dd434fbe..c6aba2a 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1743,6 +1743,10 @@
             android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, "");
             throw new SecurityException("Shortcut package name mismatch");
         }
+        final int callingUid = injectBinderCallingUid();
+        if (UserHandle.getUserId(callingUid) != si.getUserId()) {
+            throw new SecurityException("User-ID in shortcut doesn't match the caller");
+        }
     }
 
     private void verifyShortcutInfoPackages(
@@ -3611,8 +3615,8 @@
 
             // Otherwise check persisted shortcuts
             getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
-                cb.complete(getShortcutIconUriInternal(launcherUserId, launcherPackage,
-                        packageName, si, userId));
+                cb.complete(si == null ? null : getShortcutIconUriInternal(launcherUserId,
+                        launcherPackage, packageName, si, userId));
             });
         }
 
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index d32eb22..e9c6aab 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -363,14 +363,14 @@
 
     private void saveShortcutPackageItem(TypedXmlSerializer out, ShortcutPackageItem spi,
             boolean forBackup) throws IOException, XmlPullParserException {
-        spi.waitForBitmapSaves();
         if (forBackup) {
             if (spi.getPackageUserId() != spi.getOwnerUserId()) {
                 return; // Don't save cross-user information.
             }
+            spi.waitForBitmapSaves();
             spi.saveToXml(out, forBackup);
         } else {
-            spi.saveShortcutPackageItem();
+            spi.scheduleSave();
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 6f0fe63..db5b9b1 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -155,7 +155,8 @@
 
         for (PackageStateInternal ps : packages) {
             freezers.add(mPm.freezePackage(ps.getPackageName(), UserHandle.USER_ALL,
-                    "loadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER));
+                    "loadPrivatePackagesInner", ApplicationExitInfo.REASON_OTHER,
+                    null /* request */));
             synchronized (mPm.mInstallLock) {
                 final AndroidPackage pkg;
                 try {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f2797eb..803b94b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -23,6 +23,7 @@
 import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY;
 import static android.os.UserManager.USER_OPERATION_ERROR_UNKNOWN;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
 import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_ABORTED;
 import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_UNSPECIFIED;
 import static com.android.server.pm.UserJourneyLogger.ERROR_CODE_USER_ALREADY_AN_ADMIN;
@@ -2938,8 +2939,10 @@
                     UserHandle.USER_NULL, UserManager.RESTRICTION_SOURCE_SYSTEM));
         }
 
-        result.addAll(getDevicePolicyManagerInternal()
-                .getUserRestrictionSources(restrictionKey, userId));
+        final DevicePolicyManagerInternal dpmi = getDevicePolicyManagerInternal();
+        if (dpmi != null) {
+            result.addAll(dpmi.getUserRestrictionSources(restrictionKey, userId));
+        }
         return result;
     }
 
@@ -4787,11 +4790,14 @@
         // default check is for DISALLOW_ADD_USER
         // If new user is of type CLONE, check if creation of clone profile is allowed
         // If new user is of type MANAGED, check if creation of managed profile is allowed
+        // If new user is of type PRIVATE, check if creation of private profile is allowed
         String restriction = UserManager.DISALLOW_ADD_USER;
         if (UserManager.isUserTypeCloneProfile(userType)) {
             restriction = UserManager.DISALLOW_ADD_CLONE_PROFILE;
         } else if (UserManager.isUserTypeManagedProfile(userType)) {
             restriction = UserManager.DISALLOW_ADD_MANAGED_PROFILE;
+        } else if (UserManager.isUserTypePrivateProfile(userType)) {
+            restriction = UserManager.DISALLOW_ADD_PRIVATE_PROFILE;
         }
 
         enforceUserRestriction(restriction, UserHandle.getCallingUserId(),
@@ -5329,12 +5335,12 @@
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.USER_INFO,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 this::onPullAtom);
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.MULTI_USER_INFO,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 this::onPullAtom);
     }
 
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 4e2ceab..35861d7 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -103,6 +103,7 @@
             UserManager.DISALLOW_ADD_USER,
             UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             UserManager.DISALLOW_ADD_CLONE_PROFILE,
+            UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
             UserManager.ENSURE_VERIFY_APPS,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -212,7 +213,8 @@
     private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet(
             UserManager.DISALLOW_RECORD_AUDIO,
             UserManager.DISALLOW_WALLPAPER,
-            UserManager.DISALLOW_OEM_UNLOCK
+            UserManager.DISALLOW_OEM_UNLOCK,
+            UserManager.DISALLOW_ADD_PRIVATE_PROFILE
     );
 
     /**
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index b7f9aaf..85b60a0 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -51,6 +51,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 
@@ -284,9 +285,9 @@
                 .setBadgeLabels(
                         com.android.internal.R.string.private_profile_label_badge)
                 .setBadgeColors(
-                        com.android.internal.R.color.system_accent1_900)
+                        R.color.black)
                 .setDarkThemeBadgeColors(
-                        com.android.internal.R.color.system_accent1_900)
+                        R.color.white)
                 .setDefaultRestrictions(getDefaultProfileRestrictions())
                 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
                 .setDefaultUserProperties(new UserProperties.Builder()
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 3a1fd7c..8c73ce8 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -191,7 +191,7 @@
         // Perform package verification and enable rollback (unless we are simply moving the
         // package).
         if (!mOriginInfo.mExisting) {
-            if (!isApex()) {
+            if (!isApex() && !isArchivedInstallation()) {
                 // TODO(b/182426975): treat APEX as APK when APK verification is concerned
                 sendApkVerificationRequest(pkgLite);
             }
@@ -896,6 +896,9 @@
     public boolean isApex() {
         return (mInstallFlags & PackageManager.INSTALL_APEX) != 0;
     }
+    public boolean isArchivedInstallation() {
+        return (mInstallFlags & PackageManager.INSTALL_ARCHIVED) != 0;
+    }
     public boolean isStaged() {
         return mIsStaged;
     }
diff --git a/services/core/java/com/android/server/pm/flags.aconfig b/services/core/java/com/android/server/pm/flags.aconfig
index 368a843..7779c08 100644
--- a/services/core/java/com/android/server/pm/flags.aconfig
+++ b/services/core/java/com/android/server/pm/flags.aconfig
@@ -6,3 +6,11 @@
     description: "Feature flag for Quarantined state"
     bug: "269127435"
 }
+
+flag {
+    name: "new_match_uninstalled_enabled"
+    namespace: "package_manager_service"
+    description: "Feature flag for new MATCH_UNINSTALLED_PACKAGES behavior"
+    bug: "298681254"
+    is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 27812df..4eceb77 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -802,9 +802,7 @@
         // If available for the target user, or trying to match uninstalled packages and it's
         // a system app.
         return PackageUserStateUtils.isAvailable(state, flags)
-                || (pkgSetting.isSystem()
-                && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
-                || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+                || (pkgSetting.isSystem() && matchUninstalledOrHidden(flags));
     }
 
     private static boolean checkUseInstalledOrHidden(long flags,
@@ -819,9 +817,15 @@
         // If available for the target user, or trying to match uninstalled packages and it's
         // a system app.
         return PackageUserStateUtils.isAvailable(state, flags)
-                || (appInfo != null && appInfo.isSystemApp()
-                && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
-                || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
+                || (appInfo != null && appInfo.isSystemApp() && matchUninstalledOrHidden(flags));
+    }
+
+    private static boolean matchUninstalledOrHidden(long flags) {
+        return (flags
+                & (PackageManager.MATCH_KNOWN_PACKAGES
+                        | PackageManager.MATCH_ARCHIVED_PACKAGES
+                        | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS))
+                != 0;
     }
 
     private static void assignFieldsComponentInfoParsedMainComponent(
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index f5ba3f6..d82a500 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -22,6 +22,7 @@
 import android.app.ActivityThread;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.parsing.PackageLite;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
@@ -183,6 +184,23 @@
     }
 
     /**
+     * Creates a ParsedPackage from PackageLite without any additional parsing or processing.
+     * Most fields will get reasonable default values, corresponding to "deleted-keep-data".
+     */
+    @AnyThread
+    public ParsedPackage parsePackageFromPackageLite(PackageLite packageLite, int flags)
+            throws PackageManagerException {
+        ParseInput input = mSharedResult.get().reset();
+        ParseResult<ParsingPackage> result = parsingUtils.parsePackageFromPackageLite(input,
+                packageLite, flags);
+        if (result.isError()) {
+            throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
+                    result.getException());
+        }
+        return result.getResult().hideAsParsed();
+    }
+
+    /**
      * Removes the cached value for the thread the parser was created on. It is assumed that
      * any threads created for parallel parsing will be created and released, so they don't
      * need an explicit close call.
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b01a89e..fc6b12c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1024,7 +1024,9 @@
             }
 
             synchronized (mLock) {
-                mAttributions.put(source.getToken(), source);
+                // Change the token for the AttributionSource we're storing, so that we don't store
+                // a strong reference to the original token inside the map itself.
+                mAttributions.put(source.getToken(), source.withDefaultToken());
             }
         }
 
@@ -1032,7 +1034,7 @@
             synchronized (mLock) {
                 final AttributionSource cachedSource = mAttributions.get(source.getToken());
                 if (cachedSource != null) {
-                    return cachedSource.equals(source);
+                    return cachedSource.equalsExceptToken(source);
                 }
                 return false;
             }
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index b2dcf37..24323c8 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -4,7 +4,7 @@
             "name": "CtsPermissionTestCases",
             "options": [
                 {
-                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
                 },
                 {
                     "include-filter": "android.permission.cts.BackgroundPermissionsTest"
@@ -32,7 +32,7 @@
             "name": "CtsPermissionPolicyTestCases",
             "options": [
                 {
-                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
                 },
                 {
                     "include-filter": "android.permissionpolicy.cts.RestrictedPermissionsTest"
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index 7bc518c..c05b3c2 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -242,4 +242,11 @@
     @Nullable
     ArchiveState getArchiveState();
 
+    /**
+     * @return whether the data dir exists. True when the app is installed for the user, or when the
+     * app is uninstalled for the user with {@link PackageManager#DELETE_KEEP_DATA}.
+     *
+     * @hide
+     */
+    boolean dataExists();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 3534d75..fc4b686 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -196,4 +196,9 @@
     public ArchiveState getArchiveState() {
         return null;
     }
+
+    @Override
+    public boolean dataExists() {
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 2349fbf..0b35d8a 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -685,6 +685,10 @@
         return false;
     }
 
+    @Override
+    public boolean dataExists() {
+        return getCeDataInode() > 0;
+    }
 
 
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
index e342453..9ab3060 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
@@ -27,6 +27,7 @@
 import android.util.DebugUtils;
 import android.util.Slog;
 
+import com.android.server.pm.Flags;
 import com.android.server.pm.pkg.component.ParsedMainComponent;
 
 /** @hide */
@@ -82,14 +83,38 @@
         return reportIfDebug(matchesUnaware || matchesAware, flags);
     }
 
+    /**
+     * @return true if any of the following conditions is met:
+     * <p><ul>
+     * <li> If it is installed and not hidden for this user;
+     * <li> If it is installed but hidden for this user, still return true if
+     * {@link PackageManager#MATCH_UNINSTALLED_PACKAGES} or
+     * {@link PackageManager#MATCH_ARCHIVED_PACKAGES} is requested;
+     * <li> If MATCH_ANY_USER is requested, always return true, because the fact that
+     * this object exists means that the package must be installed or has data on at least one user;
+     * <li> (When feature enabled) If it is not installed but still has data (i.e., it was
+     * previously uninstalled with {@link PackageManager#DELETE_KEEP_DATA}), return true if the
+     * caller requested {@link PackageManager#MATCH_UNINSTALLED_PACKAGES} or
+     * {@link PackageManager#MATCH_ARCHIVED_PACKAGES};
+     * </ul><p>
+     */
     public static boolean isAvailable(@NonNull PackageUserState state, long flags) {
-        // True if it is installed for this user and it is not hidden. If it is hidden,
-        // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
         final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
         final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
-        return matchAnyUser
-                || (state.isInstalled()
-                && (!state.isHidden() || matchUninstalled));
+        final boolean matchArchived = (flags & PackageManager.MATCH_ARCHIVED_PACKAGES) != 0;
+        final boolean matchDataExists = matchUninstalled || matchArchived;
+
+        if (matchAnyUser) {
+            return true;
+        }
+        if (state.isInstalled()) {
+            if (!state.isHidden()) {
+                return true;
+            } else return matchDataExists;
+        } else {
+            // not installed
+            return matchDataExists && Flags.newMatchUninstalledEnabled() && state.dataExists();
+        }
     }
 
     public static boolean reportIfDebug(boolean result, long flags) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index f1f0fa3..699ccbd 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -375,6 +375,10 @@
 
     ParsingPackage setBaseRevisionCode(int baseRevisionCode);
 
+    ParsingPackage setVersionCode(int vesionCode);
+
+    ParsingPackage setVersionCodeMajor(int vesionCodeMajor);
+
     ParsingPackage setVersionName(String versionName);
 
     ParsingPackage setCompileSdkVersion(int compileSdkVersion);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index dc022f7..81c2f07 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -28,7 +28,6 @@
 import static android.os.Build.VERSION_CODES.DONUT;
 import static android.os.Build.VERSION_CODES.O;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
 import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
 
 import android.annotation.AnyRes;
@@ -474,15 +473,121 @@
         }
     }
 
-    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
-            String codePath, SplitAssetLoader assetLoader, int flags) {
-        final String apkPath = apkFile.getAbsolutePath();
+    /**
+     * Creates ParsingPackage using only PackageLite.
+     * Missing fields will contain reasonable defaults.
+     * Used for packageless (aka archived) package installation.
+     */
+    public ParseResult<ParsingPackage> parsePackageFromPackageLite(ParseInput input,
+            PackageLite lite, int flags) {
+        final String volumeUuid = getVolumeUuid(lite.getPath());
+        final String pkgName = lite.getPackageName();
 
+        final TypedArray manifestArray = null;
+        final ParsingPackage pkg = mCallback.startParsingPackage(pkgName,
+                lite.getBaseApkPath(), lite.getPath(), manifestArray, lite.isCoreApp());
+
+        final int targetSdk = lite.getTargetSdk();
+        final String versionName = null;
+        final int compileSdkVersion = 0;
+        final String compileSdkVersionCodeName = null;
+        final boolean isolatedSplitLoading = false;
+
+        // Normally set from manifestArray.
+        pkg.setVersionCode(lite.getVersionCode());
+        pkg.setVersionCodeMajor(lite.getVersionCodeMajor());
+        pkg.setBaseRevisionCode(lite.getBaseRevisionCode());
+        pkg.setVersionName(versionName);
+        pkg.setCompileSdkVersion(compileSdkVersion);
+        pkg.setCompileSdkVersionCodeName(compileSdkVersionCodeName);
+        pkg.setIsolatedSplitLoading(isolatedSplitLoading);
+        pkg.setTargetSdkVersion(targetSdk);
+
+        // parseBaseApkTags
+        pkg.setInstallLocation(lite.getInstallLocation())
+                .setTargetSandboxVersion(PARSE_DEFAULT_TARGET_SANDBOX)
+                /* Set the global "on SD card" flag */
+                .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
+
+        // parseBaseAppBasicFlags
+        pkg
+                // Default true
+                .setBackupAllowed(lite.isBackupAllowed())
+                .setClearUserDataAllowed(true)
+                .setClearUserDataOnFailedRestoreAllowed(
+                        lite.isClearUserDataOnFailedRestoreAllowed())
+                .setAllowNativeHeapPointerTagging(true)
+                .setEnabled(true)
+                .setExtractNativeLibrariesRequested(true)
+                // targetSdkVersion gated
+                .setAllowAudioPlaybackCapture(targetSdk >= Build.VERSION_CODES.Q)
+                .setHardwareAccelerated(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+                .setRequestLegacyExternalStorage(lite.isRequestLegacyExternalStorage())
+                .setCleartextTrafficAllowed(targetSdk < Build.VERSION_CODES.P)
+                // Default false
+                .setDefaultToDeviceProtectedStorage(lite.isDefaultToDeviceProtectedStorage())
+                .setUserDataFragile(lite.isUserDataFragile())
+                // Ints
+                .setCategory(ApplicationInfo.CATEGORY_UNDEFINED)
+                // Floats Default 0f
+                .setMaxAspectRatio(0f)
+                .setMinAspectRatio(0f);
+
+        // No APK - no code.
+        pkg.setDeclaredHavingCode(false);
+
+        final String taskAffinity = null;
+        ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
+                pkgName, pkgName, taskAffinity, input);
+        if (taskAffinityResult.isError()) {
+            return input.error(taskAffinityResult);
+        }
+        pkg.setTaskAffinity(taskAffinityResult.getResult());
+
+        final CharSequence pname = null;
+        ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
+                pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input);
+        if (processNameResult.isError()) {
+            return input.error(processNameResult);
+        }
+        pkg.setProcessName(processNameResult.getResult());
+
+        pkg.setGwpAsanMode(-1);
+        pkg.setMemtagMode(-1);
+
+        afterParseBaseApplication(pkg);
+
+        final ParseResult<ParsingPackage> result = validateBaseApkTags(input, pkg);
+        if (result.isError()) {
+            return result;
+        }
+
+        pkg.setVolumeUuid(volumeUuid);
+
+        if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
+            pkg.setSigningDetails(lite.getSigningDetails());
+        } else {
+            pkg.setSigningDetails(SigningDetails.UNKNOWN);
+        }
+
+        return input.success(pkg
+                .set32BitAbiPreferred(lite.isUse32bitAbi()));
+    }
+
+    private static String getVolumeUuid(final String apkPath) {
         String volumeUuid = null;
         if (apkPath.startsWith(MNT_EXPAND)) {
             final int end = apkPath.indexOf('/', MNT_EXPAND.length());
             volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
         }
+        return volumeUuid;
+    }
+
+    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
+            String codePath, SplitAssetLoader assetLoader, int flags) {
+        final String apkPath = apkFile.getAbsolutePath();
+
+        final String volumeUuid = getVolumeUuid(apkPath);
 
         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
 
@@ -882,7 +987,7 @@
         }
 
         pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,
-                R.styleable.AndroidManifest_installLocation, sa))
+                        R.styleable.AndroidManifest_installLocation, sa))
                 .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
                         R.styleable.AndroidManifest_targetSandboxVersion, sa))
                 /* Set the global "on SD card" flag */
@@ -932,6 +1037,10 @@
             }
         }
 
+        return validateBaseApkTags(input, pkg);
+    }
+
+    private ParseResult<ParsingPackage> validateBaseApkTags(ParseInput input, ParsingPackage pkg) {
         if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) {
             return input.error(
                     INSTALL_PARSE_FAILED_BAD_MANIFEST,
@@ -2199,15 +2308,19 @@
             pkg.sortServices();
         }
 
-        // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
-        // every activity info has had a chance to set it from its attributes.
+        afterParseBaseApplication(pkg);
+
+        return input.success(pkg);
+    }
+
+    // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
+    // every activity info has had a chance to set it from its attributes.
+    private void afterParseBaseApplication(ParsingPackage pkg) {
         setMaxAspectRatio(pkg);
         setMinAspectRatio(pkg);
         setSupportsSizeChanges(pkg);
 
         pkg.setHasDomainUrls(hasDomainURLs(pkg));
-
-        return input.success(pkg);
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b3aa09b..4d38239 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -559,6 +559,7 @@
     boolean mWakeOnDpadKeyPress;
     boolean mWakeOnAssistKeyPress;
     boolean mWakeOnBackKeyPress;
+    boolean mSilenceRingerOnSleepKey;
     long mWakeUpToLastStateTimeout;
     int mSearchKeyBehavior;
     ComponentName mSearchKeyTargetActivity;
@@ -606,10 +607,10 @@
     DisplayPolicy mDefaultDisplayPolicy;
 
     // What we do when the user long presses on home
-    private int mLongPressOnHomeBehavior;
+    int mLongPressOnHomeBehavior;
 
     // What we do when the user double-taps on home
-    private int mDoubleTapOnHomeBehavior;
+    int mDoubleTapOnHomeBehavior;
 
     // Must match config_primaryShortPressTargetActivity in config.xml
     ComponentName mPrimaryShortPressTargetActivity;
@@ -1423,6 +1424,15 @@
     }
 
     private void sleepRelease(long eventTime) {
+        if (mSilenceRingerOnSleepKey) {
+            TelecomManager telecomManager = getTelecommService();
+            if (telecomManager != null && telecomManager.isRinging()) {
+                telecomManager.silenceRinger();
+                Slog.i(TAG, "sleepRelease() silence ringer");
+                return;
+            }
+        }
+
         switch (mShortPressOnSleepBehavior) {
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP:
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
@@ -1843,7 +1853,9 @@
                 Settings.Secure.TV_USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
     }
 
-    private void handleShortPressOnHome(int displayId) {
+    private void handleShortPressOnHome(KeyEvent event) {
+        logKeyboardSystemsEvent(event, KeyboardLogEvent.HOME);
+
         // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
         final HdmiControl hdmiControl = getHdmiControl();
         if (hdmiControl != null) {
@@ -1859,7 +1871,7 @@
         }
 
         // Go home!
-        launchHomeFromHotKey(displayId);
+        launchHomeFromHotKey(event.getDisplayId());
     }
 
     /**
@@ -1964,17 +1976,15 @@
     private class DisplayHomeButtonHandler {
 
         private final int mDisplayId;
-
-        private boolean mHomeDoubleTapPending;
         private boolean mHomePressed;
         private boolean mHomeConsumed;
-
+        private KeyEvent mPendingHomeKeyEvent;
         private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
             @Override
             public void run() {
-                if (mHomeDoubleTapPending) {
-                    mHomeDoubleTapPending = false;
-                    handleShortPressOnHome(mDisplayId);
+                if (mPendingHomeKeyEvent != null) {
+                    handleShortPressOnHome(mPendingHomeKeyEvent);
+                    mPendingHomeKeyEvent = null;
                 }
             }
         };
@@ -1997,7 +2007,6 @@
             // If we have released the home key, and didn't do anything else
             // while it was pressed, then it is time to go home!
             if (!down) {
-                logKeyboardSystemsEvent(event, KeyboardLogEvent.HOME);
                 if (mDisplayId == DEFAULT_DISPLAY) {
                     cancelPreloadRecentApps();
                 }
@@ -2019,7 +2028,7 @@
                     if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_PIP_MENU
                             || mPictureInPictureVisible) {
                         mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
-                        mHomeDoubleTapPending = true;
+                        mPendingHomeKeyEvent = event;
                         mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
                                 ViewConfiguration.getDoubleTapTimeout());
                         return true;
@@ -2027,7 +2036,7 @@
                 }
 
                 // Post to main thread to avoid blocking input pipeline.
-                mHandler.post(() -> handleShortPressOnHome(mDisplayId));
+                mHandler.post(() -> handleShortPressOnHome(event));
                 return true;
             }
 
@@ -2053,10 +2062,10 @@
             // Remember that home is pressed and handle special actions.
             if (repeatCount == 0) {
                 mHomePressed = true;
-                if (mHomeDoubleTapPending) {
-                    mHomeDoubleTapPending = false;
+                if (mPendingHomeKeyEvent != null) {
+                    mPendingHomeKeyEvent = null;
                     mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
-                    mHandler.post(this::handleDoubleTapOnHome);
+                    mHandler.post(() -> handleDoubleTapOnHome(event));
                 // TODO(multi-display): Remove display id check once we support recents on
                 // multi-display
                 } else if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI
@@ -2066,19 +2075,19 @@
             } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
                 if (!keyguardOn) {
                     // Post to main thread to avoid blocking input pipeline.
-                    mHandler.post(() -> handleLongPressOnHome(event.getDeviceId(),
-                            event.getEventTime()));
+                    mHandler.post(() -> handleLongPressOnHome(event));
                 }
             }
             return true;
         }
 
-        private void handleDoubleTapOnHome() {
+        private void handleDoubleTapOnHome(KeyEvent event) {
             if (mHomeConsumed) {
                 return;
             }
             switch (mDoubleTapOnHomeBehavior) {
                 case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI:
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.APP_SWITCH);
                     mHomeConsumed = true;
                     toggleRecentApps();
                     break;
@@ -2093,7 +2102,7 @@
             }
         }
 
-        private void handleLongPressOnHome(int deviceId, long eventTime) {
+        private void handleLongPressOnHome(KeyEvent event) {
             if (mHomeConsumed) {
                 return;
             }
@@ -2105,13 +2114,16 @@
                     "Home - Long Press");
             switch (mLongPressOnHomeBehavior) {
                 case LONG_PRESS_HOME_ALL_APPS:
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.ALL_APPS);
                     launchAllAppsAction();
                     break;
                 case LONG_PRESS_HOME_ASSIST:
-                    launchAssistAction(null, deviceId, eventTime,
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_ASSISTANT);
+                    launchAssistAction(null, event.getDeviceId(), event.getEventTime(),
                             AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
                     break;
                 case LONG_PRESS_HOME_NOTIFICATION_PANEL:
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL);
                     toggleNotificationPanel();
                     break;
                 default:
@@ -2347,6 +2359,8 @@
                 com.android.internal.R.string.config_primaryShortPressTargetActivity));
         mShortPressOnSleepBehavior = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_shortPressOnSleepBehavior);
+        mSilenceRingerOnSleepKey = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_silenceRingerOnSleepKey);
         mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup);
 
@@ -3257,7 +3271,7 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_HOME:
-                return handleHomeShortcuts(displayId, focusedToken, event);
+                return handleHomeShortcuts(focusedToken, event);
             case KeyEvent.KEYCODE_MENU:
                 // Hijack modified menu keys for debugging features
                 final int chordBug = KeyEvent.META_SHIFT_ON;
@@ -3299,7 +3313,7 @@
             case KeyEvent.KEYCODE_H:
             case KeyEvent.KEYCODE_ENTER:
                 if (event.isMetaPressed()) {
-                    return handleHomeShortcuts(displayId, focusedToken, event);
+                    return handleHomeShortcuts(focusedToken, event);
                 }
                 break;
             case KeyEvent.KEYCODE_I:
@@ -3342,6 +3356,13 @@
                     return true;
                 }
                 break;
+            case KeyEvent.KEYCODE_DEL:
+            case KeyEvent.KEYCODE_GRAVE:
+                if (firstDown && event.isMetaPressed()) {
+                    logKeyboardSystemsEvent(event, KeyboardLogEvent.BACK);
+                    injectBackGesture(event.getDownTime());
+                    return true;
+                }
             case KeyEvent.KEYCODE_DPAD_UP:
                 if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
                     StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
@@ -3353,9 +3374,14 @@
                 }
                 break;
             case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
-                    enterStageSplitFromRunningApp(true /* leftOrTop */);
-                    logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
+                if (firstDown && event.isMetaPressed()) {
+                    if (event.isCtrlPressed()) {
+                        enterStageSplitFromRunningApp(true /* leftOrTop */);
+                        logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
+                    } else {
+                        logKeyboardSystemsEvent(event, KeyboardLogEvent.BACK);
+                        injectBackGesture(event.getDownTime());
+                    }
                     return true;
                 }
                 break;
@@ -3618,15 +3644,34 @@
         return (metaState & KeyEvent.META_META_ON) != 0;
     }
 
-    private boolean handleHomeShortcuts(int displayId, IBinder focusedToken, KeyEvent event) {
+    @SuppressLint("MissingPermission")
+    private void injectBackGesture(long downtime) {
+        // Create and inject down event
+        KeyEvent downEvent = new KeyEvent(downtime, downtime, KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
+                KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
+                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+                InputDevice.SOURCE_KEYBOARD);
+        mInputManager.injectInputEvent(downEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+
+
+        // Create and inject up event
+        KeyEvent upEvent = KeyEvent.changeAction(downEvent, KeyEvent.ACTION_UP);
+        mInputManager.injectInputEvent(upEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+
+        downEvent.recycle();
+        upEvent.recycle();
+    }
+
+    private boolean handleHomeShortcuts(IBinder focusedToken, KeyEvent event) {
         // First we always handle the home key here, so applications
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
         // timeout.
-        DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(displayId);
+        DisplayHomeButtonHandler handler = mDisplayHomeButtonHandlers.get(event.getDisplayId());
         if (handler == null) {
-            handler = new DisplayHomeButtonHandler(displayId);
-            mDisplayHomeButtonHandlers.put(displayId, handler);
+            handler = new DisplayHomeButtonHandler(event.getDisplayId());
+            mDisplayHomeButtonHandlers.put(event.getDisplayId(), handler);
         }
         return handler.handleHomeButton(focusedToken, event);
     }
@@ -5290,11 +5335,6 @@
             return false;
         }
 
-        if (theaterModeEnabled) {
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    Settings.Global.THEATER_MODE_ON, 0);
-        }
-
         mPowerManager.wakeUp(wakeTime, reason, details);
         return true;
     }
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 33bed3d..88c2e09 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power.hint;
 
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -37,7 +39,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.Preconditions;
@@ -142,7 +143,7 @@
         statsManager.setPullAtomCallback(
                 FrameworkStatsLog.ADPF_SYSTEM_COMPONENT_INFO,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 this::onPullAtom);
     }
 
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index 3a32733..f6fa9f2 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -170,10 +170,11 @@
                 && mStats.isProcessStateDataAvailable();
         final boolean includeVirtualUids =  ((query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS) != 0);
+        final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold();
 
         final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(
                 mStats.getCustomEnergyConsumerNames(), includePowerModels,
-                includeProcessStateData);
+                includeProcessStateData, minConsumedPowerThreshold);
         // TODO(b/188068523): use a monotonic clock to ensure resilience of order and duration
         // of stats sessions to wall-clock adjustments
         batteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime());
@@ -307,10 +308,12 @@
         final boolean includeProcessStateData = ((query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)
                 && mStats.isProcessStateDataAvailable();
+        final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold();
 
         final String[] customEnergyConsumerNames = mStats.getCustomEnergyConsumerNames();
         final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                customEnergyConsumerNames, includePowerModels, includeProcessStateData);
+                customEnergyConsumerNames, includePowerModels, includeProcessStateData,
+                minConsumedPowerThreshold);
         if (mBatteryUsageStatsStore == null) {
             Log.e(TAG, "BatteryUsageStatsStore is unavailable");
             return builder.build();
diff --git a/services/core/java/com/android/server/recoverysystem/hal/BootControlHIDL.java b/services/core/java/com/android/server/recoverysystem/hal/BootControlHIDL.java
index 65325c2..7c4d787 100644
--- a/services/core/java/com/android/server/recoverysystem/hal/BootControlHIDL.java
+++ b/services/core/java/com/android/server/recoverysystem/hal/BootControlHIDL.java
@@ -22,6 +22,8 @@
 import android.os.RemoteException;
 import android.util.Slog;
 
+import java.util.NoSuchElementException;
+
 public class BootControlHIDL implements IBootControl {
     private static final String TAG = "BootControlHIDL";
 
@@ -32,7 +34,7 @@
     public static boolean isServicePresent() {
         try {
             android.hardware.boot.V1_0.IBootControl.getService(true);
-        } catch (RemoteException e) {
+        } catch (RemoteException | NoSuchElementException e) {
             return false;
         }
         return true;
@@ -41,7 +43,7 @@
     public static boolean isV1_2ServicePresent() {
         try {
             android.hardware.boot.V1_2.IBootControl.getService(true);
-        } catch (RemoteException e) {
+        } catch (RemoteException | NoSuchElementException e) {
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/security/Android.bp b/services/core/java/com/android/server/security/Android.bp
new file mode 100644
index 0000000..3f644c44
--- /dev/null
+++ b/services/core/java/com/android/server/security/Android.bp
@@ -0,0 +1,17 @@
+aconfig_declarations {
+    name: "com.android.server.security.flags-aconfig",
+    package: "com.android.server.security",
+    srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "com.android.server.security.flags-aconfig-java",
+    aconfig_declarations: "com.android.server.security.flags-aconfig",
+}
+
+java_aconfig_library {
+    name: "com.android.server.security.flags-aconfig-java-host",
+    aconfig_declarations: "com.android.server.security.flags-aconfig",
+    host_supported: true,
+    test: true,
+}
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index 9529621..3aed6e3 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -27,10 +27,12 @@
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.UserHandle;
+import android.os.storage.StorageManagerInternal;
 import android.security.IFileIntegrityService;
 import android.util.Slog;
 
@@ -54,6 +56,7 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Objects;
 
 /**
  * A {@link SystemService} that provides file integrity related operations.
@@ -112,7 +115,7 @@
                     .exec(this, in, out, err, args, callback, resultReceiver);
         }
 
-        private void checkCallerPermission(String packageName) {
+        private void checkCallerPackageName(String packageName) {
             final int callingUid = Binder.getCallingUid();
             final int callingUserId = UserHandle.getUserId(callingUid);
             final PackageManagerInternal packageManager =
@@ -123,7 +126,10 @@
                 throw new SecurityException(
                         "Calling uid " + callingUid + " does not own package " + packageName);
             }
+        }
 
+        private void checkCallerPermission(String packageName) {
+            checkCallerPackageName(packageName);
             if (getContext().checkCallingPermission(android.Manifest.permission.INSTALL_PACKAGES)
                     == PackageManager.PERMISSION_GRANTED) {
                 return;
@@ -131,12 +137,43 @@
 
             final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
             final int mode = appOpsManager.checkOpNoThrow(
-                    AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, callingUid, packageName);
+                    AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, Binder.getCallingUid(), packageName);
             if (mode != AppOpsManager.MODE_ALLOWED) {
                 throw new SecurityException(
                         "Caller should have INSTALL_PACKAGES or REQUEST_INSTALL_PACKAGES");
             }
         }
+
+        @Override
+        public android.os.IInstalld.IFsveritySetupAuthToken createAuthToken(
+                ParcelFileDescriptor authFd) throws RemoteException {
+            Objects.requireNonNull(authFd);
+            try {
+                var authToken = getStorageManagerInternal().createFsveritySetupAuthToken(authFd,
+                        Binder.getCallingUid(), Binder.getCallingUserHandle().getIdentifier());
+                // fs-verity setup requires no writable fd to the file. Release the dup now that
+                // it's passed.
+                authFd.close();
+                return authToken;
+            } catch (IOException e) {
+                throw new RemoteException(e);
+            }
+        }
+
+        @Override
+        public int setupFsverity(android.os.IInstalld.IFsveritySetupAuthToken authToken,
+                String filePath, String packageName) throws RemoteException {
+            Objects.requireNonNull(authToken);
+            Objects.requireNonNull(filePath);
+            Objects.requireNonNull(packageName);
+            checkCallerPackageName(packageName);
+
+            try {
+                return getStorageManagerInternal().enableFsverity(authToken, filePath, packageName);
+            } catch (IOException e) {
+                throw new RemoteException(e);
+            }
+        }
     };
 
     public FileIntegrityService(final Context context) {
@@ -146,9 +183,19 @@
         } catch (CertificateException e) {
             Slog.wtf(TAG, "Cannot get an instance of X.509 certificate factory");
         }
+
         LocalServices.addService(FileIntegrityService.class, this);
     }
 
+    /**
+     * Returns StorageManagerInternal as a proxy to fs-verity related calls. This is to plumb
+     * the call through the canonical Installer instance in StorageManagerService, since the
+     * Installer instance isn't directly accessible.
+     */
+    private StorageManagerInternal getStorageManagerInternal() {
+        return LocalServices.getService(StorageManagerInternal.class);
+    }
+
     @Override
     public void onStart() {
         loadAllCertificates();
diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS
index 5bcc98b6..f408d7c 100644
--- a/services/core/java/com/android/server/security/OWNERS
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -1,4 +1,6 @@
 # Bug component: 36824
 
+include /core/java/android/security/OWNERS
+
 per-file *AttestationVerification* = file:/core/java/android/security/attestationverification/OWNERS
 per-file FileIntegrity*.java = victorhsieh@google.com
diff --git a/services/core/java/com/android/server/security/flags.aconfig b/services/core/java/com/android/server/security/flags.aconfig
new file mode 100644
index 0000000..0440989f
--- /dev/null
+++ b/services/core/java/com/android/server/security/flags.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.server.security"
+
+flag {
+    name: "deprecate_fsv_sig"
+    namespace: "hardware_backed_security"
+    description: "Feature flag for deprecating .fsv_sig"
+    bug: "277916185"
+}
diff --git a/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
index f744d00..565eb6e 100644
--- a/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
+++ b/services/core/java/com/android/server/sensorprivacy/CameraPrivacyLightController.java
@@ -18,7 +18,6 @@
 
 import static android.hardware.SensorManager.SENSOR_DELAY_NORMAL;
 
-import android.annotation.ColorInt;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.hardware.Sensor;
@@ -39,6 +38,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.FgThread;
 
 import java.util.ArrayDeque;
@@ -48,12 +48,10 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
-
 class CameraPrivacyLightController implements AppOpsManager.OnOpActiveChangedListener,
         SensorEventListener {
 
-    @VisibleForTesting
-    static final double LIGHT_VALUE_MULTIPLIER = 1 / Math.log(1.1);
+    private static final double LIGHT_VALUE_MULTIPLIER = 1 / Math.log(1.1);
 
     private final Handler mHandler;
     private final Executor mExecutor;
@@ -69,11 +67,6 @@
 
     private LightsManager.LightsSession mLightsSession = null;
 
-    @ColorInt
-    private final int mDayColor;
-    @ColorInt
-    private final int mNightColor;
-
     private final Sensor mLightSensor;
 
     private boolean mIsAmbientLightListenerRegistered = false;
@@ -81,7 +74,9 @@
     /** When average of the time integral over the past {@link #mMovingAverageIntervalMillis}
      *  milliseconds of the log_1.1(lux(t)) is greater than this value, use the daytime brightness
      *  else use nighttime brightness. */
-    private final long mNightThreshold;
+    private final long[] mThresholds;
+
+    private final int[] mColors;
     private final ArrayDeque<Pair<Long, Integer>> mAmbientLightValues = new ArrayDeque<>();
     /** Tracks the Riemann sum of {@link #mAmbientLightValues} to avoid O(n) operations when sum is
      *  needed */
@@ -101,6 +96,20 @@
 
     @VisibleForTesting
     CameraPrivacyLightController(Context context, Looper looper) {
+        mColors = context.getResources().getIntArray(R.array.config_cameraPrivacyLightColors);
+        if (ArrayUtils.isEmpty(mColors)) {
+            mHandler = null;
+            mExecutor = null;
+            mContext = null;
+            mAppOpsManager = null;
+            mLightsManager = null;
+            mSensorManager = null;
+            mLightSensor = null;
+            mMovingAverageIntervalMillis = 0;
+            mThresholds = null;
+            // Return here before this class starts interacting with other services.
+            return;
+        }
         mContext = context;
 
         mHandler = new Handler(looper);
@@ -109,14 +118,20 @@
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
         mLightsManager = mContext.getSystemService(LightsManager.class);
         mSensorManager = mContext.getSystemService(SensorManager.class);
-
-        mDayColor = mContext.getColor(R.color.camera_privacy_light_day);
-        mNightColor = mContext.getColor(R.color.camera_privacy_light_night);
         mMovingAverageIntervalMillis = mContext.getResources()
                 .getInteger(R.integer.config_cameraPrivacyLightAlsAveragingIntervalMillis);
-        mNightThreshold = (long) (Math.log(mContext.getResources()
-                .getInteger(R.integer.config_cameraPrivacyLightAlsNightThreshold))
-                * LIGHT_VALUE_MULTIPLIER);
+        int[] thresholdsLux = mContext.getResources().getIntArray(
+                R.array.config_cameraPrivacyLightAlsLuxThresholds);
+        if (thresholdsLux.length != mColors.length - 1) {
+            throw new IllegalStateException("There must be exactly one more color than thresholds."
+                    + " Found " + mColors.length + " colors and " + thresholdsLux.length
+                    + " thresholds.");
+        }
+        mThresholds = new long[thresholdsLux.length];
+        for (int i = 0; i < thresholdsLux.length; i++) {
+            int luxValue = thresholdsLux[i];
+            mThresholds[i] = (long) (Math.log(luxValue) * LIGHT_VALUE_MULTIPLIER);
+        }
 
         List<Light> lights = mLightsManager.getLights();
         for (int i = 0; i < lights.size(); i++) {
@@ -223,13 +238,8 @@
             mLightsSession.close();
             mLightsSession = null;
         } else {
-            int lightColor;
-            if (mLightSensor != null && getLiveAmbientLightTotal()
-                    < getCurrentIntervalMillis() * mNightThreshold) {
-                lightColor = mNightColor;
-            } else {
-                lightColor = mDayColor;
-            }
+            int lightColor =
+                    mLightSensor == null ? mColors[mColors.length - 1] : computeCurrentLightColor();
 
             if (mLastLightColor == lightColor && mLightsSession != null) {
                 return;
@@ -252,6 +262,18 @@
         }
     }
 
+    private int computeCurrentLightColor() {
+        long liveAmbientLightTotal = getLiveAmbientLightTotal();
+        long currentInterval = getCurrentIntervalMillis();
+
+        for (int i = 0; i < mThresholds.length; i++) {
+            if (liveAmbientLightTotal < currentInterval * mThresholds[i]) {
+                return mColors[i];
+            }
+        }
+        return mColors[mColors.length - 1];
+    }
+
     private void updateSensorListener(boolean shouldSessionEnd) {
         if (shouldSessionEnd && mIsAmbientLightListenerRegistered) {
             mSensorManager.unregisterListener(this);
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 5d04e5d..97420d0 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1599,7 +1599,7 @@
         mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 mStatsCallbackImpl
         );
     }
@@ -1612,7 +1612,7 @@
         mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 mStatsCallbackImpl
         );
     }
@@ -1625,7 +1625,7 @@
         mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
-                BackgroundThread.getExecutor(),
+                DIRECT_EXECUTOR,
                 mStatsCallbackImpl
         );
     }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 415d05e..0043122 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -120,9 +120,6 @@
     private final BroadcastReceiver mTrustableDowngradeReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (!TrustManagerService.ENABLE_ACTIVE_UNLOCK_FLAG) {
-                return;
-            }
             // are these the broadcasts we want to listen to
             if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
                 downgradeToTrustable();
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index bed69fc..9905ddf 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -31,7 +31,6 @@
 import android.app.trust.ITrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -42,11 +41,9 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -58,7 +55,6 @@
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -162,13 +158,6 @@
     private final ActivityManager mActivityManager;
     private VirtualDeviceManagerInternal mVirtualDeviceManager;
 
-    @GuardedBy("mUserIsTrusted")
-    private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
-
-    //TODO(b/215724686): remove flag
-    public static final boolean ENABLE_ACTIVE_UNLOCK_FLAG = SystemProperties.getBoolean(
-            "fw.enable_active_unlock_flag", true);
-
     private enum TrustState {
         UNTRUSTED, // the phone is not unlocked by any trustagents
         TRUSTABLE, // the phone is in a semi-locked state that can be unlocked if
@@ -229,7 +218,6 @@
             mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>();
     private AlarmManager mAlarmManager;
     private final Object mAlarmLock = new Object();
-    private final SettingsObserver mSettingsObserver;
 
     private final StrongAuthTracker mStrongAuthTracker;
 
@@ -271,7 +259,6 @@
         mLockPatternUtils = injector.getLockPatternUtils();
         mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper());
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        mSettingsObserver = new SettingsObserver(mHandler);
     }
 
     @Override
@@ -299,103 +286,10 @@
         }
     }
 
-    // Extend unlock config and logic
-    private final class SettingsObserver extends ContentObserver {
-        private final Uri TRUST_AGENTS_EXTEND_UNLOCK =
-                Settings.Secure.getUriFor(Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK);
-
-        private final Uri LOCK_SCREEN_WHEN_TRUST_LOST =
-                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST);
-
-        private final boolean mIsAutomotive;
-        private final ContentResolver mContentResolver;
-        private boolean mTrustAgentsNonrenewableTrust;
-        private boolean mLockWhenTrustLost;
-
-        /**
-         * Creates a settings observer
-         *
-         * @param handler The handler to run {@link #onChange} on, or null if none.
-         */
-        SettingsObserver(Handler handler) {
-            super(handler);
-
-            PackageManager packageManager = getContext().getPackageManager();
-            mIsAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
-
-            mContentResolver = getContext().getContentResolver();
-            updateContentObserver();
-        }
-
-        void updateContentObserver() {
-            mContentResolver.unregisterContentObserver(this);
-            mContentResolver.registerContentObserver(TRUST_AGENTS_EXTEND_UNLOCK,
-                    false /* notifyForDescendents */,
-                    this /* observer */,
-                    mCurrentUser);
-            mContentResolver.registerContentObserver(LOCK_SCREEN_WHEN_TRUST_LOST,
-                    false /* notifyForDescendents */,
-                    this /* observer */,
-                    mCurrentUser);
-
-            // Update the value immediately
-            onChange(true /* selfChange */, TRUST_AGENTS_EXTEND_UNLOCK);
-            onChange(true /* selfChange */, LOCK_SCREEN_WHEN_TRUST_LOST);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            if (TRUST_AGENTS_EXTEND_UNLOCK.equals(uri)) {
-                // Smart lock should only grant non-renewable trust. The only exception is for
-                // automotive, where it can actively unlock the head unit.
-                int defaultValue = mIsAutomotive ? 0 : 1;
-
-                mTrustAgentsNonrenewableTrust =
-                        Settings.Secure.getIntForUser(
-                                mContentResolver,
-                                Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
-                                defaultValue,
-                                mCurrentUser) != 0;
-            } else if (LOCK_SCREEN_WHEN_TRUST_LOST.equals(uri)) {
-                mLockWhenTrustLost =
-                        Settings.Secure.getIntForUser(
-                                mContentResolver,
-                                Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
-                                0 /* default */,
-                                mCurrentUser) != 0;
-            }
-        }
-
-        boolean getTrustAgentsNonrenewableTrust() {
-            return mTrustAgentsNonrenewableTrust;
-        }
-
-        boolean getLockWhenTrustLost() {
-            return mLockWhenTrustLost;
-        }
-    }
-
-    private void maybeLockScreen(int userId) {
-        if (userId != mCurrentUser) {
-            return;
-        }
-
-        if (mSettingsObserver.getLockWhenTrustLost()) {
-            if (DEBUG) Slog.d(TAG, "Locking device because trust was lost");
-            try {
-                WindowManagerGlobal.getWindowManagerService().lockNow(null);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Error locking screen when trust was lost");
-            }
-
-            // If active unlocking is not allowed, cancel any pending trust timeouts because the
-            // screen is already locked.
-            TrustedTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
-            if (alarm != null && mSettingsObserver.getTrustAgentsNonrenewableTrust()) {
-                mAlarmManager.cancel(alarm);
-                alarm.setQueued(false /* isQueued */);
-            }
-        }
+    // Automotive head units can be unlocked by a trust agent, even when the agent doesn't use
+    // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE.
+    private boolean isAutomotive() {
+        return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
     private void scheduleTrustTimeout(boolean override, boolean isTrustableTimeout) {
@@ -569,69 +463,6 @@
             int flags,
             boolean isFromUnlock,
             @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
-        if (ENABLE_ACTIVE_UNLOCK_FLAG) {
-            updateTrustWithRenewableUnlock(userId, flags, isFromUnlock, resultCallback);
-        } else {
-            updateTrustWithNonrenewableTrust(userId, flags, isFromUnlock);
-        }
-    }
-
-    private void updateTrustWithNonrenewableTrust(int userId, int flags, boolean isFromUnlock) {
-        boolean managed = aggregateIsTrustManaged(userId);
-        dispatchOnTrustManagedChanged(managed, userId);
-        if (mStrongAuthTracker.isTrustAllowedForUser(userId)
-                && isTrustUsuallyManagedInternal(userId) != managed) {
-            updateTrustUsuallyManaged(userId, managed);
-        }
-
-        boolean trusted = aggregateIsTrusted(userId);
-        IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
-        boolean showingKeyguard = true;
-        try {
-            showingKeyguard = wm.isKeyguardLocked();
-        } catch (RemoteException e) {
-        }
-
-        boolean changed;
-        synchronized (mUserIsTrusted) {
-            if (mSettingsObserver.getTrustAgentsNonrenewableTrust()) {
-                // For non-renewable trust agents can only set the device to trusted if it already
-                // trusted or the device is unlocked. Attempting to set the device as trusted
-                // when the device is locked will be ignored.
-                changed = mUserIsTrusted.get(userId) != trusted;
-                trusted = trusted
-                        && (!showingKeyguard || isFromUnlock || !changed)
-                        && userId == mCurrentUser;
-                if (DEBUG) {
-                    Slog.d(TAG, "Extend unlock setting trusted as " + Boolean.toString(trusted)
-                            + " && " + Boolean.toString(!showingKeyguard)
-                            + " && " + Boolean.toString(userId == mCurrentUser));
-                }
-            }
-            changed = mUserIsTrusted.get(userId) != trusted;
-            mUserIsTrusted.put(userId, trusted);
-        }
-        dispatchOnTrustChanged(
-                trusted,
-                false /* newlyUnlocked */,
-                userId,
-                flags,
-                getTrustGrantedMessages(userId));
-        if (changed) {
-            refreshDeviceLockedForUser(userId);
-            if (!trusted) {
-                maybeLockScreen(userId);
-            } else {
-                scheduleTrustTimeout(false /* override */, false /* isTrustableTimeout*/);
-            }
-        }
-    }
-
-    private void updateTrustWithRenewableUnlock(
-            int userId,
-            int flags,
-            boolean isFromUnlock,
-            @Nullable AndroidFuture<GrantTrustResult> resultCallback) {
         boolean managed = aggregateIsTrustManaged(userId);
         dispatchOnTrustManagedChanged(managed, userId);
         if (mStrongAuthTracker.isTrustAllowedForUser(userId)
@@ -655,12 +486,10 @@
         synchronized (mUserTrustState) {
             wasTrusted = (mUserTrustState.get(userId) == TrustState.TRUSTED);
             wasTrustable = (mUserTrustState.get(userId) == TrustState.TRUSTABLE);
-            boolean isAutomotive = getContext().getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_AUTOMOTIVE);
             boolean renewingTrust = wasTrustable && (
                     (flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0);
             boolean canMoveToTrusted =
-                    alreadyUnlocked || isFromUnlock || renewingTrust || isAutomotive;
+                    alreadyUnlocked || isFromUnlock || renewingTrust || isAutomotive();
             boolean upgradingTrustForCurrentUser = (userId == mCurrentUser);
 
             if (trustedByAtLeastOneAgent && wasTrusted) {
@@ -687,9 +516,7 @@
                 isNowTrusted, newlyUnlocked, userId, flags, getTrustGrantedMessages(userId));
         if (isNowTrusted != wasTrusted) {
             refreshDeviceLockedForUser(userId);
-            if (!isNowTrusted) {
-                maybeLockScreen(userId);
-            } else {
+            if (isNowTrusted) {
                 boolean isTrustableTimeout =
                         (flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0;
                 // Every time we grant renewable trust we should override the idle trustable
@@ -1899,9 +1726,7 @@
             synchronized(mUsersUnlockedByBiometric) {
                 mUsersUnlockedByBiometric.put(userId, true);
             }
-            // In non-renewable trust mode we need to refresh trust state here, which will call
-            // refreshDeviceLockedForUser()
-            int updateTrustOnUnlock = mSettingsObserver.getTrustAgentsNonrenewableTrust() ? 1 : 0;
+            int updateTrustOnUnlock = isAutomotive() ? 0 : 1;
             mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER, userId,
                     updateTrustOnUnlock).sendToTarget();
             mHandler.obtainMessage(MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH, userId).sendToTarget();
@@ -2010,7 +1835,6 @@
                         break;
                     case MSG_SWITCH_USER:
                         mCurrentUser = msg.arg1;
-                        mSettingsObserver.updateContentObserver();
                         refreshDeviceLockedForUser(UserHandle.USER_ALL);
                         break;
                     case MSG_STOP_USER:
@@ -2109,9 +1933,6 @@
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 int userId = getUserId(intent);
                 if (userId > 0) {
-                    synchronized (mUserIsTrusted) {
-                        mUserIsTrusted.delete(userId);
-                    }
                     synchronized (mDeviceLockedForUser) {
                         mDeviceLockedForUser.delete(userId);
                     }
@@ -2243,7 +2064,6 @@
                 mLockPatternUtils.requireStrongAuth(
                         mStrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED, mUserId);
             }
-            maybeLockScreen(mUserId);
         }
 
         protected abstract void handleAlarm();
@@ -2265,16 +2085,11 @@
 
         @Override
         public void handleAlarm() {
-            TrustableTimeoutAlarmListener otherAlarm;
-            boolean otherAlarmPresent;
-            if (ENABLE_ACTIVE_UNLOCK_FLAG) {
-                otherAlarm = mTrustableTimeoutAlarmListenerForUser.get(mUserId);
-                otherAlarmPresent = (otherAlarm != null) && otherAlarm.isQueued();
-                if (otherAlarmPresent) {
-                    synchronized (mAlarmLock) {
-                        disableNonrenewableTrustWhileRenewableTrustIsPresent();
-                    }
-                    return;
+            TrustableTimeoutAlarmListener otherAlarm =
+                    mTrustableTimeoutAlarmListenerForUser.get(mUserId);
+            if (otherAlarm != null && otherAlarm.isQueued()) {
+                synchronized (mAlarmLock) {
+                    disableNonrenewableTrustWhileRenewableTrustIsPresent();
                 }
             }
         }
@@ -2299,17 +2114,11 @@
 
         @Override
         public void handleAlarm() {
-            TrustedTimeoutAlarmListener otherAlarm;
-            boolean otherAlarmPresent;
-            if (ENABLE_ACTIVE_UNLOCK_FLAG) {
-                cancelBothTrustableAlarms(mUserId);
-                otherAlarm = mTrustTimeoutAlarmListenerForUser.get(mUserId);
-                otherAlarmPresent = (otherAlarm != null) && otherAlarm.isQueued();
-                if (otherAlarmPresent) {
-                    synchronized (mAlarmLock) {
-                        disableRenewableTrustWhileNonrenewableTrustIsPresent();
-                    }
-                    return;
+            cancelBothTrustableAlarms(mUserId);
+            TrustedTimeoutAlarmListener otherAlarm = mTrustTimeoutAlarmListenerForUser.get(mUserId);
+            if (otherAlarm != null && otherAlarm.isQueued()) {
+                synchronized (mAlarmLock) {
+                    disableRenewableTrustWhileNonrenewableTrustIsPresent();
                 }
             }
         }
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 0ab6d57..06a8516 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -96,6 +96,8 @@
     /* A map from a HDMI logical address to the matching TV input ID. */
     private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>();
     private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>();
+    /* A map from a HDMI input parent ID to the related input IDs. */
+    private final Map<String, List<String>> mHdmiParentInputMap = new ArrayMap<>();
 
     private final AudioManager mAudioManager;
     private final IHdmiHotplugEventListener mHdmiHotplugEventListener =
@@ -293,6 +295,12 @@
         }
     }
 
+    public Map<String, List<String>> getHdmiParentInputMap() {
+        synchronized (mLock) {
+            return Collections.unmodifiableMap(mHdmiParentInputMap);
+        }
+    }
+
     private boolean checkUidChangedLocked(
             Connection connection, int callingUid, int resolvedUserId) {
         Integer connectionCallingUid = connection.getCallingUidLocked();
@@ -379,12 +387,15 @@
             }
             mHdmiInputIdMap.put(id, info.getId());
             mInputMap.put(info.getId(), info);
+            if (!mHdmiParentInputMap.containsKey(parentId)) {
+                mHdmiParentInputMap.put(parentId, new ArrayList<String>());
+            }
+            mHdmiParentInputMap.get(parentId).add(info.getId());
         }
     }
 
     public void removeHardwareInput(String inputId) {
         synchronized (mLock) {
-            mInputMap.remove(inputId);
             int hardwareIndex = indexOfEqualValue(mHardwareInputIdMap, inputId);
             if (hardwareIndex >= 0) {
                 mHardwareInputIdMap.removeAt(hardwareIndex);
@@ -393,6 +404,17 @@
             if (deviceIndex >= 0) {
                 mHdmiInputIdMap.removeAt(deviceIndex);
             }
+            if (mInputMap.containsKey(inputId)) {
+                String parentId = mInputMap.get(inputId).getParentId();
+                if (parentId != null && mHdmiParentInputMap.containsKey(parentId)) {
+                    List<String> parentInputList = mHdmiParentInputMap.get(parentId);
+                    parentInputList.remove(inputId);
+                    if (parentInputList.isEmpty()) {
+                        mHdmiParentInputMap.remove(parentId);
+                    }
+                }
+                mInputMap.remove(inputId);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 7ea9870..b12ecc3 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -41,6 +41,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiDeviceInfo;
@@ -94,6 +95,7 @@
 import android.view.InputChannel;
 import android.view.Surface;
 
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
@@ -177,6 +179,11 @@
 
     private final ActivityManager mActivityManager;
 
+    private boolean mExternalInputLoggingDisplayNameFilterEnabled = false;
+    private final HashSet<String> mExternalInputLoggingDeviceOnScreenDisplayNames =
+            new HashSet<String>();
+    private final List<String> mExternalInputLoggingDeviceBrandNames = new ArrayList<String>();
+
     public TvInputManagerService(Context context) {
         super(context);
 
@@ -192,6 +199,8 @@
         synchronized (mLock) {
             getOrCreateUserStateLocked(mCurrentUserId);
         }
+
+        initExternalInputLoggingConfigs();
     }
 
     @Override
@@ -224,6 +233,21 @@
         }
     }
 
+    private void initExternalInputLoggingConfigs() {
+        mExternalInputLoggingDisplayNameFilterEnabled = mContext.getResources().getBoolean(
+                R.bool.config_tvExternalInputLoggingDisplayNameFilterEnabled);
+        if (!mExternalInputLoggingDisplayNameFilterEnabled) {
+            return;
+        }
+        final String[] deviceOnScreenDisplayNames = mContext.getResources().getStringArray(
+                R.array.config_tvExternalInputLoggingDeviceOnScreenDisplayNames);
+        final String[] deviceBrandNames = mContext.getResources().getStringArray(
+                R.array.config_tvExternalInputLoggingDeviceBrandNames);
+        mExternalInputLoggingDeviceOnScreenDisplayNames.addAll(
+                Arrays.asList(deviceOnScreenDisplayNames));
+        mExternalInputLoggingDeviceBrandNames.addAll(Arrays.asList(deviceBrandNames));
+    }
+
     private void registerBroadcastReceivers() {
         PackageMonitor monitor = new PackageMonitor() {
             private void buildTvInputList(String[] packages) {
@@ -1815,22 +1839,22 @@
                         getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
                                 channelUri, params);
                         UserState userState = getOrCreateUserStateLocked(resolvedUserId);
-                        SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
-                                userState);
+                        SessionState sessionState =
+                                getSessionStateLocked(sessionToken, callingUid, userState);
                         if (!sessionState.isCurrent
                                 || !Objects.equals(sessionState.currentChannel, channelUri)) {
                             sessionState.isCurrent = true;
                             sessionState.currentChannel = channelUri;
                             notifyCurrentChannelInfosUpdatedLocked(userState);
                             if (!sessionState.isRecordingSession) {
-                                if (mOnScreenInputId == null
-                                    || !TextUtils.equals(mOnScreenInputId, sessionState.inputId)) {
+                                String actualInputId = getActualInputId(sessionState);
+                                if (!TextUtils.equals(mOnScreenInputId, actualInputId)) {
                                     logExternalInputEvent(
-                                        FrameworkStatsLog
-                                                .EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
-                                        sessionState.inputId, sessionState);
+                                            FrameworkStatsLog
+                                                    .EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
+                                            actualInputId, sessionState);
                                 }
-                                mOnScreenInputId = sessionState.inputId;
+                                mOnScreenInputId = actualInputId;
                                 mOnScreenSessionState = sessionState;
                             }
                         }
@@ -2953,6 +2977,31 @@
         }
     }
 
+    // get the actual input id of the specific sessionState.
+    // e.g. if an HDMI port has a CEC device plugged in, the actual input id of the HDMI
+    // session should be the input id of CEC device instead of the default HDMI input id.
+    @GuardedBy("mLock")
+    private String getActualInputId(SessionState sessionState) {
+        UserState userState = getOrCreateUserStateLocked(sessionState.userId);
+        TvInputState tvInputState = userState.inputMap.get(sessionState.inputId);
+        TvInputInfo tvInputInfo = tvInputState.info;
+        String actualInputId = sessionState.inputId;
+        switch (tvInputInfo.getType()) {
+            case TvInputInfo.TYPE_HDMI:
+                // TODO: find a better approach towards active CEC device in future
+                Map<String, List<String>> hdmiParentInputMap =
+                        mTvInputHardwareManager.getHdmiParentInputMap();
+                if (hdmiParentInputMap.containsKey(sessionState.inputId)) {
+                    List<String> parentInputList = hdmiParentInputMap.get(sessionState.inputId);
+                    actualInputId = parentInputList.get(0);
+                }
+                break;
+            default:
+                break;
+        }
+        return actualInputId;
+    }
+
     @Nullable
     private static TvInputState getTvInputState(
             SessionState sessionState,
@@ -3054,6 +3103,7 @@
                 hdmiPort);
     }
 
+    @GuardedBy("mLock")
     private void logExternalInputEvent(int eventType, String inputId, SessionState sessionState) {
         UserState userState = getOrCreateUserStateLocked(sessionState.userId);
         TvInputState tvInputState = userState.inputMap.get(inputId);
@@ -3073,13 +3123,32 @@
                 hdmiPort = hdmiDeviceInfo.getPortId();
                 if (hdmiDeviceInfo.isCecDevice()) {
                     displayName = hdmiDeviceInfo.getDisplayName();
+                    if (mExternalInputLoggingDisplayNameFilterEnabled) {
+                        displayName = filterExternalInputLoggingDisplayName(displayName);
+                    }
                     vendorId = hdmiDeviceInfo.getVendorId();
                 }
             }
         }
 
         FrameworkStatsLog.write(FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT, eventType, inputState,
-                inputType, displayName, vendorId, hdmiPort, tifSessionId);
+                inputType, vendorId, hdmiPort, tifSessionId, displayName);
+    }
+
+    private String filterExternalInputLoggingDisplayName(String displayName) {
+        String nullDisplayName = "NULL_DISPLAY_NAME", filteredDisplayName = "FILTERED_DISPLAY_NAME";
+        if (displayName == null) {
+            return nullDisplayName;
+        }
+        if (mExternalInputLoggingDeviceOnScreenDisplayNames.contains(displayName)) {
+            return displayName;
+        }
+        for (String brandName : mExternalInputLoggingDeviceBrandNames) {
+            if (displayName.toUpperCase().contains(brandName.toUpperCase())) {
+                return brandName;
+            }
+        }
+        return filteredDisplayName;
     }
 
     private static final class UserState {
@@ -3429,6 +3498,10 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
+                    if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
+                        return;
+                    }
                     mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
                     addHardwareInputLocked(inputInfo);
                 }
@@ -3443,6 +3516,10 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
+                    if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
+                        return;
+                    }
                     mTvInputHardwareManager.addHdmiInput(id, inputInfo);
                     addHardwareInputLocked(inputInfo);
                     if (mOnScreenInputId != null && mOnScreenSessionState != null) {
@@ -3566,13 +3643,14 @@
                         mSessionState.currentChannel = channelUri;
                         notifyCurrentChannelInfosUpdatedLocked(userState);
                         if (!mSessionState.isRecordingSession) {
-                            if (mOnScreenInputId == null
-                                || !TextUtils.equals(mOnScreenInputId, mSessionState.inputId)) {
+                            String actualInputId = getActualInputId(mSessionState);
+                            if (!TextUtils.equals(mOnScreenInputId, actualInputId)) {
                                 logExternalInputEvent(
-                                    FrameworkStatsLog.EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
-                                    mSessionState.inputId, mSessionState);
+                                        FrameworkStatsLog
+                                                .EXTERNAL_TV_INPUT_EVENT__EVENT_TYPE__TUNED,
+                                        actualInputId, mSessionState);
                             }
-                            mOnScreenInputId = mSessionState.inputId;
+                            mOnScreenInputId = actualInputId;
                             mOnScreenSessionState = mSessionState;
                         }
                     }
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 01fdc88..7862f58 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -41,6 +41,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
@@ -62,6 +63,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -1304,6 +1306,46 @@
         return false;
     }
 
+    /**
+     * Check if the targetPkg can be granted permission to access uri by
+     * the callingUid using the given modeFlags. See {@link #checkGrantUriPermissionUnlocked}.
+     *
+     * @param callingUid The uid of the grantor app that has permissions to the uri.
+     * @param targetPkg The package name of the granted app that needs permissions to the uri.
+     * @param uri The uri for which permissions should be granted.
+     * @param modeFlags The modes to grant. See {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}, etc.
+     * @param userId The userId in which the uri is to be resolved.
+     * @return uid of the target or -1 if permission grant not required. Returns -1 if the caller
+     *  does not hold INTERACT_ACROSS_USERS_FULL
+     * @throws SecurityException if the grant is not allowed.
+     */
+    @Override
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    public int checkGrantUriPermission_ignoreNonSystem(int callingUid, String targetPkg, Uri uri,
+            int modeFlags, int userId) {
+        if (!isCallerIsSystemOrPrivileged()) {
+            return Process.INVALID_UID;
+        }
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            return checkGrantUriPermissionUnlocked(callingUid, targetPkg, uri, modeFlags,
+                        userId);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    private boolean isCallerIsSystemOrPrivileged() {
+        final int uid = Binder.getCallingUid();
+        if (uid == Process.SYSTEM_UID || uid == Process.ROOT_UID) {
+            return true;
+        }
+        return ActivityManager.checkComponentPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    uid, /* owningUid = */-1, /* exported = */ true)
+                    == PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public ArrayList<UriPermission> providePersistentUriGrants() {
         final ArrayList<UriPermission> result = new ArrayList<>();
diff --git a/services/core/java/com/android/server/utils/FoldSettingProvider.java b/services/core/java/com/android/server/utils/FoldSettingProvider.java
new file mode 100644
index 0000000..d62628b
--- /dev/null
+++ b/services/core/java/com/android/server/utils/FoldSettingProvider.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import java.util.Set;
+
+/**
+ * This class provides a convenient way to access the {@link Settings.System#FOLD_LOCK_BEHAVIOR}.
+ * The {@link Settings.System#FOLD_LOCK_BEHAVIOR} setting controls the behavior of the device when
+ * it is folded, and provides the user with three different options to choose from. Those are:
+ * 1. Stay awake on fold: The device will remain unlocked when it is folded.
+ * 2. Selective stay awake: The device will remain unlocked when it is folded only if there are
+ * apps with wakelocks running. This is also the set default behavior.
+ * 3. Sleep on fold: The device will lock when it is folded, regardless of which apps are running
+ * or whether any wakelocks are held.
+ *
+ * Keep the setting values in this class in sync with the values in
+ * {@link com.android.settings.display.FoldLockBehaviorSettings}
+ */
+public class FoldSettingProvider {
+
+    public static final String SETTING_VALUE_STAY_AWAKE_ON_FOLD = "stay_awake_on_fold_key";
+    public static final String SETTING_VALUE_SELECTIVE_STAY_AWAKE = "selective_stay_awake_key";
+    public static final String SETTING_VALUE_SLEEP_ON_FOLD = "sleep_on_fold_key";
+    private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
+    private static final Set<String> SETTING_VALUES = Set.of(SETTING_VALUE_STAY_AWAKE_ON_FOLD,
+            SETTING_VALUE_SELECTIVE_STAY_AWAKE, SETTING_VALUE_SLEEP_ON_FOLD);
+    private static final String TAG = "FoldSettingProvider";
+
+    private final ContentResolver mContentResolver;
+    private final boolean mIsFoldLockBehaviorAvailable;
+    private final SettingsWrapper mSettingsWrapper;
+
+    public FoldSettingProvider(Context context, SettingsWrapper settingsWrapper) {
+        mContentResolver = context.getContentResolver();
+        mSettingsWrapper = settingsWrapper;
+        mIsFoldLockBehaviorAvailable = context.getResources().getBoolean(
+                R.bool.config_fold_lock_behavior);
+    }
+
+    /**
+     * Returns whether the device should remain awake after folding.
+     */
+    public boolean shouldStayAwakeOnFold() {
+        return getFoldSettingValue().equals(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+    }
+
+    /**
+     * Returns whether the device should selective remain awake after folding.
+     */
+    public boolean shouldSelectiveStayAwakeOnFold() {
+        return getFoldSettingValue().equals(SETTING_VALUE_SELECTIVE_STAY_AWAKE);
+    }
+
+    /**
+     * Returns whether the device should strictly sleep after folding.
+     */
+    public boolean shouldSleepOnFold() {
+        return getFoldSettingValue().equals(SETTING_VALUE_SLEEP_ON_FOLD);
+    }
+
+    private String getFoldSettingValue() {
+        if (!mIsFoldLockBehaviorAvailable) {
+            return SETTING_VALUE_DEFAULT;
+        }
+        String foldSettingValue = mSettingsWrapper.getStringForUser(
+                mContentResolver,
+                Settings.System.FOLD_LOCK_BEHAVIOR,
+                UserHandle.USER_CURRENT);
+        foldSettingValue = (foldSettingValue != null) ? foldSettingValue : SETTING_VALUE_DEFAULT;
+        if (!SETTING_VALUES.contains(foldSettingValue)) {
+            Log.e(TAG,
+                    "getFoldSettingValue: Invalid setting value, returning default setting value");
+            foldSettingValue = SETTING_VALUE_DEFAULT;
+        }
+
+        return foldSettingValue;
+    }
+}
diff --git a/services/core/java/com/android/server/utils/FoldSettingWrapper.java b/services/core/java/com/android/server/utils/FoldSettingWrapper.java
deleted file mode 100644
index 97a1ac0..0000000
--- a/services/core/java/com/android/server/utils/FoldSettingWrapper.java
+++ /dev/null
@@ -1,48 +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.server.utils;
-
-import android.content.ContentResolver;
-import android.provider.Settings;
-
-/**
- * A wrapper class for the {@link Settings.System#STAY_AWAKE_ON_FOLD} setting.
- *
- * This class provides a convenient way to access the {@link Settings.System#STAY_AWAKE_ON_FOLD}
- * setting for testing.
- */
-public class FoldSettingWrapper {
-    private final ContentResolver mContentResolver;
-
-    public FoldSettingWrapper(ContentResolver contentResolver) {
-        mContentResolver = contentResolver;
-    }
-
-    /**
-     * Returns whether the device should remain awake after folding.
-     */
-    public boolean shouldStayAwakeOnFold() {
-        try {
-            return (Settings.System.getIntForUser(
-                    mContentResolver,
-                    Settings.System.STAY_AWAKE_ON_FOLD,
-                    0) == 1);
-        } catch (Settings.SettingNotFoundException e) {
-            return false;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
index 3fb845f..e4f9607 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackCustomization.java
@@ -19,7 +19,7 @@
 import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.os.VibrationEffect;
-import android.os.Vibrator;
+import android.os.VibratorInfo;
 import android.os.vibrator.persistence.ParsedVibration;
 import android.os.vibrator.persistence.VibrationXmlParser;
 import android.text.TextUtils;
@@ -107,10 +107,10 @@
      * @hide
      */
     @Nullable
-    static SparseArray<VibrationEffect> loadVibrations(Resources res, Vibrator vibrator)
+    static SparseArray<VibrationEffect> loadVibrations(Resources res, VibratorInfo vibratorInfo)
             throws CustomizationParserException, IOException {
         try {
-            return loadVibrationsInternal(res, vibrator);
+            return loadVibrationsInternal(res, vibratorInfo);
         } catch (VibrationXmlParser.VibrationXmlParserException
                 | XmlParserException
                 | XmlPullParserException e) {
@@ -121,7 +121,7 @@
 
     @Nullable
     private static SparseArray<VibrationEffect> loadVibrationsInternal(
-            Resources res, Vibrator vibrator) throws
+            Resources res, VibratorInfo vibratorInfo) throws
                     CustomizationParserException,
                     IOException,
                     VibrationXmlParser.VibrationXmlParserException,
@@ -175,7 +175,7 @@
                 throw new CustomizationParserException(
                         "Unable to parse vibration element for effect " + effectId);
             }
-            VibrationEffect effect = parsedVibration.resolve(vibrator);
+            VibrationEffect effect = parsedVibration.resolve(vibratorInfo);
             if (effect != null) {
                 if (effect.getDuration() == Long.MAX_VALUE) {
                     throw new CustomizationParserException(String.format(
diff --git a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
index 7c99543..3d89afa 100644
--- a/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
+++ b/services/core/java/com/android/server/vibrator/HapticFeedbackVibrationProvider.java
@@ -21,6 +21,7 @@
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.os.VibratorInfo;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.HapticFeedbackConstants;
@@ -29,8 +30,6 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.HashSet;
-import java.util.Set;
 
 /**
  * Provides the {@link VibrationEffect} and {@link VibrationAttributes} for haptic feedback.
@@ -47,7 +46,7 @@
     private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
 
-    private final Vibrator mVibrator;
+    private final VibratorInfo mVibratorInfo;
     private final boolean mHapticTextHandleEnabled;
     // Vibrator effect for haptic feedback during boot when safe mode is enabled.
     private final VibrationEffect mSafeModeEnabledVibrationEffect;
@@ -58,25 +57,25 @@
 
     /** @hide */
     public HapticFeedbackVibrationProvider(Resources res, Vibrator vibrator) {
-        this(res, vibrator, loadHapticCustomizations(res, vibrator));
+        this(res, vibrator.getInfo());
+    }
+
+    /** @hide */
+    public HapticFeedbackVibrationProvider(Resources res, VibratorInfo vibratorInfo) {
+        this(res, vibratorInfo, loadHapticCustomizations(res, vibratorInfo));
     }
 
     /** @hide */
     @VisibleForTesting HapticFeedbackVibrationProvider(
             Resources res,
-            Vibrator vibrator,
+            VibratorInfo vibratorInfo,
             @Nullable SparseArray<VibrationEffect> hapticCustomizations) {
-        mVibrator = vibrator;
+        mVibratorInfo = vibratorInfo;
         mHapticTextHandleEnabled = res.getBoolean(
                 com.android.internal.R.bool.config_enableHapticTextHandle);
 
-        if (hapticCustomizations != null) {
-            // Clean up the customizations to remove vibrations which may not ever be used due to
-            // Vibrator properties or other device configurations.
-            removeUnsupportedVibrations(hapticCustomizations, vibrator);
-            if (hapticCustomizations.size() == 0) {
-                hapticCustomizations = null;
-            }
+        if (hapticCustomizations != null && hapticCustomizations.size() == 0) {
+            hapticCustomizations = null;
         }
         mHapticCustomizations = hapticCustomizations;
 
@@ -257,7 +256,7 @@
         if (effectHasCustomization(hapticFeedbackId)) {
             return mHapticCustomizations.get(hapticFeedbackId);
         }
-        if (mVibrator.areAllPrimitivesSupported(primitiveId)) {
+        if (mVibratorInfo.isPrimitiveSupported(primitiveId)) {
             return VibrationEffect.startComposition()
                     .addPrimitive(primitiveId, primitiveScale)
                     .compose();
@@ -270,9 +269,8 @@
         if (effectHasCustomization(HapticFeedbackConstants.ASSISTANT_BUTTON)) {
             return mHapticCustomizations.get(HapticFeedbackConstants.ASSISTANT_BUTTON);
         }
-        if (mVibrator.areAllPrimitivesSupported(
-                VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
-                VibrationEffect.Composition.PRIMITIVE_TICK)) {
+        if (mVibratorInfo.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+                && mVibratorInfo.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK)) {
             // quiet ramp, short pause, then sharp tick
             return VibrationEffect.startComposition()
                     .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 0.25f)
@@ -289,27 +287,12 @@
 
     @Nullable
     private static SparseArray<VibrationEffect> loadHapticCustomizations(
-            Resources res, Vibrator vibrator) {
+            Resources res, VibratorInfo vibratorInfo) {
         try {
-            return HapticFeedbackCustomization.loadVibrations(res, vibrator);
+            return HapticFeedbackCustomization.loadVibrations(res, vibratorInfo);
         } catch (IOException | HapticFeedbackCustomization.CustomizationParserException e) {
             Slog.e(TAG, "Unable to load haptic customizations.", e);
             return null;
         }
     }
-
-    private static void removeUnsupportedVibrations(
-            SparseArray<VibrationEffect> customizations, Vibrator vibrator) {
-        Set<Integer> keysToRemove = new HashSet<>();
-        for (int i = 0; i < customizations.size(); i++) {
-            int key = customizations.keyAt(i);
-            if (!vibrator.areVibrationFeaturesSupported(customizations.get(key))) {
-                keysToRemove.add(key);
-            }
-        }
-
-        for (int key : keysToRemove) {
-            customizations.remove(key);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index e296c7b..ee3d697 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.hardware.vibrator.IVibrator;
 import android.os.BatteryStats;
 import android.os.Binder;
@@ -131,6 +132,7 @@
 
     private final Object mLock = new Object();
     private final Context mContext;
+    private final Injector mInjector;
     private final PowerManager.WakeLock mWakeLock;
     private final IBatteryStats mBatteryStatsService;
     private final VibratorFrameworkStatsLogger mFrameworkStatsLogger;
@@ -162,6 +164,8 @@
 
     @GuardedBy("mLock")
     @Nullable private VibratorInfo mCombinedVibratorInfo;
+    @GuardedBy("mLock")
+    @Nullable private HapticFeedbackVibrationProvider mHapticFeedbackVibrationProvider;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -201,6 +205,7 @@
     @VisibleForTesting
     VibratorManagerService(Context context, Injector injector) {
         mContext = context;
+        mInjector = injector;
         mHandler = injector.createHandler(Looper.myLooper());
 
         mVibrationSettings = new VibrationSettings(mContext, mHandler);
@@ -393,7 +398,42 @@
     @Override // Binder call
     public void vibrate(int uid, int displayId, String opPkg, @NonNull CombinedVibration effect,
             @Nullable VibrationAttributes attrs, String reason, IBinder token) {
-        vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token);
+        vibrateWithPermissionCheck(uid, displayId, opPkg, effect, attrs, reason, token);
+    }
+
+    @Override // Binder call
+    public void performHapticFeedback(
+            int uid, int displayId, String opPkg, int constant, boolean always, String reason,
+            IBinder token) {
+        performHapticFeedbackInternal(uid, displayId, opPkg, constant, always, reason, token);
+    }
+
+    /**
+     * An internal-only version of performHapticFeedback that allows the caller access to the
+     * {@link HalVibration}.
+     * The Vibration is only returned if it is ongoing after this method returns.
+     */
+    @VisibleForTesting
+    @Nullable
+    HalVibration performHapticFeedbackInternal(
+            int uid, int displayId, String opPkg, int constant, boolean always, String reason,
+            IBinder token) {
+        HapticFeedbackVibrationProvider hapticVibrationProvider = getHapticVibrationProvider();
+        if (hapticVibrationProvider == null) {
+            Slog.w(TAG, "performHapticFeedback; haptic vibration provider not ready.");
+            return null;
+        }
+        VibrationEffect effect = hapticVibrationProvider.getVibrationForHapticFeedback(constant);
+        if (effect == null) {
+            Slog.w(TAG, "performHapticFeedback; vibration absent for effect " + constant);
+            return null;
+        }
+        CombinedVibration combinedVibration = CombinedVibration.createParallel(effect);
+        VibrationAttributes attrs =
+                hapticVibrationProvider.getVibrationAttributesForHapticFeedback(
+                        constant, /* bypassVibrationIntensitySetting= */ always);
+        return vibrateWithoutPermissionCheck(uid, displayId, opPkg, combinedVibration, attrs,
+                "performHapticFeedback: " + reason, token);
     }
 
     /**
@@ -403,93 +443,110 @@
      */
     @VisibleForTesting
     @Nullable
-    HalVibration vibrateInternal(int uid, int displayId, String opPkg,
+    HalVibration vibrateWithPermissionCheck(int uid, int displayId, String opPkg,
             @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
             String reason, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
         try {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.VIBRATE, "vibrate");
-
-            if (token == null) {
-                Slog.e(TAG, "token must not be null");
-                return null;
-            }
-            enforceUpdateAppOpsStatsPermission(uid);
-            if (!isEffectValid(effect)) {
-                return null;
-            }
-            attrs = fixupVibrationAttributes(attrs, effect);
-            // Create Vibration.Stats as close to the received request as possible, for tracking.
-            HalVibration vib = new HalVibration(token, effect,
-                    new Vibration.CallerInfo(attrs, uid, displayId, opPkg, reason));
-            fillVibrationFallbacks(vib, effect);
-
-            if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
-                // Force update of user settings before checking if this vibration effect should
-                // be ignored or scaled.
-                mVibrationSettings.update();
-            }
-
-            synchronized (mLock) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Starting vibrate for vibration " + vib.id);
-                }
-
-                // Check if user settings or DnD is set to ignore this vibration.
-                Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(vib.callerInfo);
-
-                // Check if ongoing vibration is more important than this vibration.
-                if (vibrationEndInfo == null) {
-                    vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(vib);
-                }
-
-                // If not ignored so far then try to start this vibration.
-                if (vibrationEndInfo == null) {
-                    final long ident = Binder.clearCallingIdentity();
-                    try {
-                        if (mCurrentExternalVibration != null) {
-                            mCurrentExternalVibration.mute();
-                            vib.stats.reportInterruptedAnotherVibration(
-                                    mCurrentExternalVibration.callerInfo);
-                            endExternalVibrateLocked(
-                                    new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
-                                            vib.callerInfo),
-                                    /* continueExternalControl= */ false);
-                        } else if (mCurrentVibration != null) {
-                            if (mCurrentVibration.getVibration().canPipelineWith(vib)) {
-                                // Don't cancel the current vibration if it's pipeline-able.
-                                // Note that if there is a pending next vibration that can't be
-                                // pipelined, it will have already cancelled the current one, so we
-                                // don't need to consider it here as well.
-                                if (DEBUG) {
-                                    Slog.d(TAG, "Pipelining vibration " + vib.id);
-                                }
-                            } else {
-                                vib.stats.reportInterruptedAnotherVibration(
-                                        mCurrentVibration.getVibration().callerInfo);
-                                mCurrentVibration.notifyCancelled(
-                                        new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
-                                                vib.callerInfo),
-                                        /* immediate= */ false);
-                            }
-                        }
-                        vibrationEndInfo = startVibrationLocked(vib);
-                    } finally {
-                        Binder.restoreCallingIdentity(ident);
-                    }
-                }
-
-                // Ignored or failed to start the vibration, end it and report metrics right away.
-                if (vibrationEndInfo != null) {
-                    endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ true);
-                }
-                return vib;
-            }
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.VIBRATE, "vibrate");
+            return vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
         }
     }
 
+    HalVibration vibrateWithoutPermissionCheck(int uid, int displayId, String opPkg,
+            @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
+            String reason, IBinder token) {
+        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate no perm check, reason = " + reason);
+        try {
+            return vibrateInternal(uid, displayId, opPkg, effect, attrs, reason, token);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+        }
+    }
+
+    private HalVibration vibrateInternal(int uid, int displayId, String opPkg,
+            @NonNull CombinedVibration effect, @Nullable VibrationAttributes attrs,
+            String reason, IBinder token) {
+        if (token == null) {
+            Slog.e(TAG, "token must not be null");
+            return null;
+        }
+        enforceUpdateAppOpsStatsPermission(uid);
+        if (!isEffectValid(effect)) {
+            return null;
+        }
+        attrs = fixupVibrationAttributes(attrs, effect);
+        // Create Vibration.Stats as close to the received request as possible, for tracking.
+        HalVibration vib = new HalVibration(token, effect,
+                new Vibration.CallerInfo(attrs, uid, displayId, opPkg, reason));
+        fillVibrationFallbacks(vib, effect);
+
+        if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
+            // Force update of user settings before checking if this vibration effect should
+            // be ignored or scaled.
+            mVibrationSettings.update();
+        }
+
+        synchronized (mLock) {
+            if (DEBUG) {
+                Slog.d(TAG, "Starting vibrate for vibration " + vib.id);
+            }
+
+            // Check if user settings or DnD is set to ignore this vibration.
+            Vibration.EndInfo vibrationEndInfo = shouldIgnoreVibrationLocked(vib.callerInfo);
+
+            // Check if ongoing vibration is more important than this vibration.
+            if (vibrationEndInfo == null) {
+                vibrationEndInfo = shouldIgnoreVibrationForOngoingLocked(vib);
+            }
+
+            // If not ignored so far then try to start this vibration.
+            if (vibrationEndInfo == null) {
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    if (mCurrentExternalVibration != null) {
+                        mCurrentExternalVibration.mute();
+                        vib.stats.reportInterruptedAnotherVibration(
+                                mCurrentExternalVibration.callerInfo);
+                        endExternalVibrateLocked(
+                                new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+                                        vib.callerInfo),
+                                /* continueExternalControl= */ false);
+                    } else if (mCurrentVibration != null) {
+                        if (mCurrentVibration.getVibration().canPipelineWith(vib)) {
+                            // Don't cancel the current vibration if it's pipeline-able.
+                            // Note that if there is a pending next vibration that can't be
+                            // pipelined, it will have already cancelled the current one, so we
+                            // don't need to consider it here as well.
+                            if (DEBUG) {
+                                Slog.d(TAG, "Pipelining vibration " + vib.id);
+                            }
+                        } else {
+                            vib.stats.reportInterruptedAnotherVibration(
+                                    mCurrentVibration.getVibration().callerInfo);
+                            mCurrentVibration.notifyCancelled(
+                                    new Vibration.EndInfo(Vibration.Status.CANCELLED_SUPERSEDED,
+                                            vib.callerInfo),
+                                    /* immediate= */ false);
+                        }
+                    }
+                    vibrationEndInfo = startVibrationLocked(vib);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+
+            // Ignored or failed to start the vibration, end it and report metrics right away.
+            if (vibrationEndInfo != null) {
+                endVibrationLocked(vib, vibrationEndInfo, /* shouldWriteStats= */ true);
+            }
+            return vib;
+        }
+    }
+
     @Override // Binder call
     public void cancelVibrate(int usageFilter, IBinder token) {
         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "cancelVibrate");
@@ -1315,6 +1372,11 @@
             return new VibratorController(vibratorId, listener);
         }
 
+        HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
+                Resources resources, VibratorInfo vibratorInfo) {
+            return new HapticFeedbackVibrationProvider(resources, vibratorInfo);
+        }
+
         void addService(String name, IBinder service) {
             ServiceManager.addService(name, service);
         }
@@ -1831,6 +1893,22 @@
         }
     }
 
+    private HapticFeedbackVibrationProvider getHapticVibrationProvider() {
+        synchronized (mLock) {
+            // Used a cached haptic vibration provider if one exists.
+            if (mHapticFeedbackVibrationProvider != null) {
+                return mHapticFeedbackVibrationProvider;
+            }
+            VibratorInfo combinedVibratorInfo = getCombinedVibratorInfo();
+            if (combinedVibratorInfo == null) {
+                return null;
+            }
+            return mHapticFeedbackVibrationProvider =
+                    mInjector.createHapticFeedbackVibrationProvider(
+                            mContext.getResources(), combinedVibratorInfo);
+        }
+    }
+
     private VibratorInfo getCombinedVibratorInfo() {
         synchronized (mLock) {
             // Used a cached resolving vibrator if one exists.
@@ -2068,6 +2146,9 @@
                 if ("cancel".equals(cmd)) {
                     return runCancel();
                 }
+                if ("feedback".equals(cmd)) {
+                    return runHapticFeedback();
+                }
                 return handleDefaultCommands(cmd);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
@@ -2098,16 +2179,10 @@
             // only cancel background vibrations.
             IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
                     : mShellCallbacksToken;
-            HalVibration vib = vibrateInternal(Binder.getCallingUid(), Display.DEFAULT_DISPLAY,
-                    SHELL_PACKAGE_NAME, combined, attrs, commonOptions.description, deathBinder);
-            if (vib != null && !commonOptions.background) {
-                try {
-                    // Waits for the client vibration to finish, but the VibrationThread may still
-                    // do cleanup after this.
-                    vib.waitForEnd();
-                } catch (InterruptedException e) {
-                }
-            }
+            HalVibration vib = vibrateWithPermissionCheck(Binder.getCallingUid(),
+                    Display.DEFAULT_DISPLAY, SHELL_PACKAGE_NAME, combined, attrs,
+                    commonOptions.description, deathBinder);
+            maybeWaitOnVibration(vib, commonOptions);
         }
 
         private int runMono() {
@@ -2155,6 +2230,21 @@
             return 0;
         }
 
+        private int runHapticFeedback() {
+            CommonOptions commonOptions = new CommonOptions();
+            int constant = Integer.parseInt(getNextArgRequired());
+
+            IBinder deathBinder = commonOptions.background ? VibratorManagerService.this
+                    : mShellCallbacksToken;
+            HalVibration vib = performHapticFeedbackInternal(Binder.getCallingUid(),
+                    Display.DEFAULT_DISPLAY, SHELL_PACKAGE_NAME, constant,
+                    /* always= */ commonOptions.force, /* reason= */ commonOptions.description,
+                    deathBinder);
+            maybeWaitOnVibration(vib, commonOptions);
+
+            return 0;
+        }
+
         private VibrationEffect nextEffect() {
             VibrationEffect.Composition composition = VibrationEffect.startComposition();
             String nextArg;
@@ -2364,6 +2454,17 @@
             }
         }
 
+        private void maybeWaitOnVibration(HalVibration vib, CommonOptions commonOptions) {
+            if (vib != null && !commonOptions.background) {
+                try {
+                    // Waits for the client vibration to finish, but the VibrationThread may still
+                    // do cleanup after this.
+                    vib.waitForEnd();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
         @Override
         public void onHelp() {
             try (PrintWriter pw = getOutPrintWriter();) {
@@ -2389,6 +2490,10 @@
                 pw.println("    XML containing a single effect it runs on all vibrators in sync.");
                 pw.println("  cancel");
                 pw.println("    Cancels any active vibration");
+                pw.println("  feedback [-f] [-d <description>] <constant>");
+                pw.println("    Performs a haptic feedback with the given constant.");
+                pw.println("    The force (-f) option enables the `always` configuration, which");
+                pw.println("    plays the haptic irrespective of the vibration intensity settings");
                 pw.println("");
                 pw.println("Effect commands:");
                 pw.println("  oneshot [-w delay] [-a] <duration> [<amplitude>]");
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 598c1ae..ddc0519 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2000,7 +2000,12 @@
             WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) {
 
         if (serviceInfo == null) {
-            clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply);
+            if (wallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)) {
+                clearWallpaperLocked(FLAG_SYSTEM, wallpaper.userId, null);
+                clearWallpaperLocked(FLAG_LOCK, wallpaper.userId, reply);
+            } else {
+                clearWallpaperLocked(wallpaper.mWhich, wallpaper.userId, reply);
+            }
             return;
         }
         Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
@@ -2032,7 +2037,7 @@
         WallpaperData data = null;
         synchronized (mLock) {
             if (mIsLockscreenLiveWallpaperEnabled) {
-                clearWallpaperLocked(callingPackage, which, userId, null);
+                clearWallpaperLocked(callingPackage, which, userId);
             } else {
                 clearWallpaperLocked(which, userId, null);
             }
@@ -2052,8 +2057,7 @@
         }
     }
 
-    private void clearWallpaperLocked(String callingPackage, int which, int userId,
-            IRemoteCallback reply) {
+    private void clearWallpaperLocked(String callingPackage, int which, int userId) {
 
         // Might need to bring it in the first time to establish our rewrite
         if (!mWallpaperMap.contains(userId)) {
@@ -2092,8 +2096,8 @@
                 finalWhich = which;
             }
 
-            boolean success = withCleanCallingIdentity(() -> setWallpaperComponentInternal(
-                    component, callingPackage, finalWhich, userId, reply));
+            boolean success = withCleanCallingIdentity(() -> setWallpaperComponent(
+                    component, callingPackage, finalWhich, userId));
             if (success) return;
         } catch (IllegalArgumentException e1) {
             e = e1;
@@ -2105,23 +2109,10 @@
         // wallpaper.
         Slog.e(TAG, "Default wallpaper component not found!", e);
         withCleanCallingIdentity(() -> clearWallpaperComponentLocked(wallpaper));
-        if (reply != null) {
-            try {
-                reply.sendResult(null);
-            } catch (RemoteException e1) {
-                Slog.w(TAG, "Failed to notify callback after wallpaper clear", e1);
-            }
-        }
     }
 
+    // TODO(b/266818039) remove this version of the method
     private void clearWallpaperLocked(int which, int userId, IRemoteCallback reply) {
-
-        if (mIsLockscreenLiveWallpaperEnabled) {
-            String callingPackage = mPackageManagerInternal.getNameForUid(getCallingUid());
-            clearWallpaperLocked(callingPackage, which, userId, reply);
-            return;
-        }
-
         if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
             throw new IllegalArgumentException("Must specify exactly one kind of wallpaper to clear");
         }
@@ -3293,7 +3284,7 @@
     boolean setWallpaperComponent(ComponentName name, String callingPackage,
             @SetWallpaperFlags int which, int userId) {
         if (mIsLockscreenLiveWallpaperEnabled) {
-            return setWallpaperComponentInternal(name, callingPackage, which, userId, null);
+            return setWallpaperComponentInternal(name, callingPackage, which, userId);
         } else {
             setWallpaperComponentInternalLegacy(name, callingPackage, which, userId);
             return true;
@@ -3301,7 +3292,7 @@
     }
 
     private boolean setWallpaperComponentInternal(ComponentName name, String callingPackage,
-            @SetWallpaperFlags int which, int userIdIn, IRemoteCallback reply) {
+            @SetWallpaperFlags int which, int userIdIn) {
         if (DEBUG) {
             Slog.v(TAG, "Setting new live wallpaper: which=" + which + ", component: " + name);
         }
@@ -3350,7 +3341,6 @@
                             Slog.d(TAG, "publish system wallpaper changed!");
                         }
                         liveSync.complete();
-                        if (reply != null) reply.sendResult(null);
                     }
                 };
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9eec5f8..582536b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -225,7 +225,6 @@
 import static com.android.server.wm.LetterboxConfiguration.DEFAULT_LETTERBOX_ASPECT_RATIO_FOR_MULTI_WINDOW;
 import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
 import static com.android.server.wm.StartingData.AFTER_TRANSACTION_COPY_TO_CLIENT;
-import static com.android.server.wm.StartingData.AFTER_TRANSACTION_IDLE;
 import static com.android.server.wm.StartingData.AFTER_TRANSACTION_REMOVE_DIRECTLY;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK;
@@ -2698,7 +2697,8 @@
 
     private void requestCopySplashScreen() {
         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_COPYING;
-        if (!mAtmService.mTaskOrganizerController.copySplashScreenView(getTask())) {
+        if (mStartingSurface == null || !mAtmService.mTaskOrganizerController.copySplashScreenView(
+                getTask(), mStartingSurface.mTaskOrganizer)) {
             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
             removeStartingWindow();
         }
@@ -2711,12 +2711,14 @@
      */
     void onCopySplashScreenFinish(SplashScreenViewParcelable parcelable) {
         removeTransferSplashScreenTimeout();
-        // unable to copy from shell, maybe it's not a splash screen. or something went wrong.
-        // either way, abort and reset the sequence.
-        if (parcelable == null
+        final SurfaceControl windowAnimationLeash = (parcelable == null
                 || mTransferringSplashScreenState != TRANSFER_SPLASH_SCREEN_COPYING
                 || mStartingWindow == null || mStartingWindow.mRemoved
-                || finishing) {
+                || finishing) ? null
+                : TaskOrganizerController.applyStartingWindowAnimation(mStartingWindow);
+        if (windowAnimationLeash == null) {
+            // Unable to copy from shell, maybe it's not a splash screen, or something went wrong.
+            // Either way, abort and reset the sequence.
             if (parcelable != null) {
                 parcelable.clearIfNeeded();
             }
@@ -2724,9 +2726,6 @@
             removeStartingWindow();
             return;
         }
-        // schedule attach splashScreen to client
-        final SurfaceControl windowAnimationLeash = TaskOrganizerController
-                .applyStartingWindowAnimation(mStartingWindow);
         try {
             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT;
             mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), token,
@@ -2766,7 +2765,8 @@
                 && (mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_FINISH
                 || mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_IDLE)) {
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Cleaning splash screen token=%s", this);
-            mAtmService.mTaskOrganizerController.onAppSplashScreenViewRemoved(getTask());
+            mAtmService.mTaskOrganizerController.onAppSplashScreenViewRemoved(getTask(),
+                    mStartingSurface != null ? mStartingSurface.mTaskOrganizer : null);
         }
     }
 
@@ -2854,7 +2854,6 @@
         } else if (lastData.mRemoveAfterTransaction == AFTER_TRANSACTION_COPY_TO_CLIENT) {
             removeStartingWindow();
         }
-        lastData.mRemoveAfterTransaction = AFTER_TRANSACTION_IDLE;
     }
 
     void removeStartingWindowAnimation(boolean prepareAnimation) {
@@ -2930,7 +2929,7 @@
         reparent(newTaskFrag, position);
     }
 
-    private boolean isHomeIntent(Intent intent) {
+    static boolean isHomeIntent(Intent intent) {
         return ACTION_MAIN.equals(intent.getAction())
                 && (intent.hasCategory(CATEGORY_HOME)
                 || intent.hasCategory(CATEGORY_SECONDARY_HOME))
@@ -3364,7 +3363,11 @@
         // current focused activity could be another activity in the same Task if activities are
         // displayed on adjacent TaskFragments.
         final ActivityRecord currentFocusedApp = mDisplayContent.mFocusedApp;
-        if (currentFocusedApp != null && currentFocusedApp.task == task) {
+        final int topFocusedDisplayId = mRootWindowContainer.getTopFocusedDisplayContent() != null
+                ? mRootWindowContainer.getTopFocusedDisplayContent().getDisplayId()
+                : INVALID_DISPLAY;
+        if (currentFocusedApp != null && currentFocusedApp.task == task
+                && topFocusedDisplayId == mDisplayContent.getDisplayId()) {
             final Task topFocusableTask = mDisplayContent.getTask(
                     (t) -> t.isLeafTask() && t.isFocusable(), true /*  traverseTopToBottom */);
             if (task == topFocusableTask) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1eb56f1..a5b1132 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -55,6 +55,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -77,7 +78,6 @@
 
     private final ActivityTaskManagerService mService;
     private final ActivityTaskSupervisor mSupervisor;
-    private final RootWindowContainer mRootWindowContainer;
     private final Context mServiceContext;
 
     // UserManager cannot be final as it's not ready when this class is instantiated during boot
@@ -110,17 +110,23 @@
     TaskFragment mInTaskFragment;
     ActivityOptions mActivityOptions;
 
+    /*
+     * Note that this is just a hint of what the launch display area will be as it is
+     * based only on the information at the early pre-interception stage of starting the
+     * intent. The real launch display area calculated later may be different from this one.
+     */
+    TaskDisplayArea mPresumableLaunchDisplayArea;
+
     ActivityStartInterceptor(
             ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) {
-        this(service, supervisor, service.mRootWindowContainer, service.mContext);
+        this(service, supervisor, service.mContext);
     }
 
     @VisibleForTesting
     ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor,
-            RootWindowContainer root, Context context) {
+            Context context) {
         mService = service;
         mSupervisor = supervisor;
-        mRootWindowContainer = root;
         mServiceContext = context;
     }
 
@@ -162,7 +168,7 @@
     /**
      * A helper function to obtain the targeted {@link TaskFragment} during
      * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int,
-     * ActivityOptions)} if any.
+     * ActivityOptions, TaskDisplayArea)} if any.
      */
     @Nullable
     private TaskFragment getLaunchTaskFragment() {
@@ -187,7 +193,7 @@
      */
     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
             Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
-            ActivityOptions activityOptions) {
+            ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea) {
         mUserManager = UserManager.get(mServiceContext);
 
         mIntent = intent;
@@ -199,6 +205,7 @@
         mInTask = inTask;
         mInTaskFragment = inTaskFragment;
         mActivityOptions = activityOptions;
+        mPresumableLaunchDisplayArea = presumableLaunchDisplayArea;
 
         if (interceptQuietProfileIfNeeded()) {
             // If work profile is turned off, skip the work challenge since the profile can only
@@ -221,6 +228,11 @@
         if (interceptLockedManagedProfileIfNeeded()) {
             return true;
         }
+        if (interceptHomeIfNeeded()) {
+            // Replace primary home intents directed at displays that do not support primary home
+            // but support secondary home with the relevant secondary home activity.
+            return true;
+        }
 
         final SparseArray<ActivityInterceptorCallback> callbacks =
                 mService.getActivityInterceptorCallbacks();
@@ -470,6 +482,47 @@
         return true;
     }
 
+    private boolean interceptHomeIfNeeded() {
+        if (mPresumableLaunchDisplayArea == null || mService.mRootWindowContainer == null) {
+            return false;
+        }
+        if (!ActivityRecord.isHomeIntent(mIntent)) {
+            return false;
+        }
+        if (!mIntent.hasCategory(Intent.CATEGORY_HOME)) {
+            // Already a secondary home intent, leave it alone.
+            return false;
+        }
+        if (mService.mRootWindowContainer.shouldPlacePrimaryHomeOnDisplay(
+                mPresumableLaunchDisplayArea.getDisplayId())) {
+            // Primary home can be launched to the display area.
+            return false;
+        }
+        if (!mService.mRootWindowContainer.shouldPlaceSecondaryHomeOnDisplayArea(
+                mPresumableLaunchDisplayArea)) {
+            // Secondary home cannot be launched on the display area.
+            return false;
+        }
+
+        // At this point we have a primary home intent for a display that does not support primary
+        // home activity but it supports secondary home one. So replace it with secondary home.
+        Pair<ActivityInfo, Intent> info = mService.mRootWindowContainer
+                .resolveSecondaryHomeActivity(mUserId, mPresumableLaunchDisplayArea);
+        mIntent = info.second;
+        // The new task flag is needed because the home activity should already be in the root task
+        // and should not be moved to the caller's task. Also, activities cannot change their type,
+        // e.g. a standard activity cannot become a home activity.
+        mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0,
+                mRealCallingUid, mRealCallingPid);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/ null);
+        return true;
+    }
+
     private boolean isPackageSuspended() {
         return mAInfo != null && mAInfo.applicationInfo != null
                 && (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) != 0;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1bc78d6..458d1e8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1154,10 +1154,12 @@
             }
         }
 
+        final TaskDisplayArea suggestedLaunchDisplayArea =
+                computeSuggestedLaunchDisplayArea(inTask, sourceRecord, checkedOptions);
         mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
                 callingFeatureId);
         if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
-                callingPid, callingUid, checkedOptions)) {
+                callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea)) {
             // activity start was intercepted, e.g. because the target user is currently in quiet
             // mode (turn off work) or the target application is suspended
             intent = mInterceptor.mIntent;
@@ -1890,6 +1892,15 @@
         mPreferredWindowingMode = mLaunchParams.mWindowingMode;
     }
 
+    private TaskDisplayArea computeSuggestedLaunchDisplayArea(
+            Task task, ActivityRecord source, ActivityOptions options) {
+        mSupervisor.getLaunchParamsController().calculate(task, /*layout=*/null,
+                /*activity=*/ null, source, options, mRequest, PHASE_DISPLAY, mLaunchParams);
+        return mLaunchParams.hasPreferredTaskDisplayArea()
+                ? mLaunchParams.mPreferredTaskDisplayArea
+                : mRootWindowContainer.getDefaultTaskDisplayArea();
+    }
+
     @VisibleForTesting
     int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
         if (r.packageName == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 59159bb..fd42077 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2648,9 +2648,15 @@
             mAmInternal.enforceCallingPermission(Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
                     "updateLockTaskPackages()");
         }
-        synchronized (mGlobalLock) {
-            ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowlisting %d:%s", userId, Arrays.toString(packages));
-            getLockTaskController().updateLockTaskPackages(userId, packages);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                ProtoLog.w(WM_DEBUG_LOCKTASK, "Allowlisting %d:%s", userId,
+                        Arrays.toString(packages));
+                getLockTaskController().updateLockTaskPackages(userId, packages);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -4048,10 +4054,6 @@
         mRecentTasks.notifyTaskPersisterLocked(task, flush);
     }
 
-    boolean isKeyguardLocked(int displayId) {
-        return mKeyguardController.isKeyguardLocked(displayId);
-    }
-
     /**
      * Clears launch params for the given package.
      *
@@ -6181,6 +6183,8 @@
         @Override
         public void onPackageReplaced(ApplicationInfo aInfo) {
             synchronized (mGlobalLock) {
+                // In case if setWindowManager hasn't been called yet when booting.
+                if (mRootWindowContainer == null) return;
                 mRootWindowContainer.updateActivityApplicationInfo(aInfo);
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index eb15b31..6eb9ed69 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -794,6 +794,14 @@
             return false;
         }
 
+        // Try pausing the existing resumed activity in the same TaskFragment if any.
+        final TaskFragment taskFragment = r.getTaskFragment();
+        if (taskFragment != null && taskFragment.getResumedActivity() != null) {
+            if (taskFragment.startPausing(mUserLeaving, false /* uiSleeping */, r, "realStart")) {
+                return false;
+            }
+        }
+
         final Task task = r.getTask();
         final Task rootTask = task.getRootTask();
 
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 4180cd2..15a0445 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -40,8 +40,6 @@
     private static final boolean DEBUG = false;
 
     // Desktop mode feature flags.
-    private static final boolean DESKTOP_MODE_PROTO1_SUPPORTED =
-            SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false);
     private static final boolean DESKTOP_MODE_PROTO2_SUPPORTED =
             SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
     // Override default freeform task width when desktop mode is enabled. In dips.
@@ -142,6 +140,6 @@
 
     /** Whether desktop mode is supported. */
     static boolean isDesktopModeSupported() {
-        return DESKTOP_MODE_PROTO1_SUPPORTED || DESKTOP_MODE_PROTO2_SUPPORTED;
+        return DESKTOP_MODE_PROTO2_SUPPORTED;
     }
 }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 4f3ab8b..ae29afa 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -22,6 +22,7 @@
 import static com.android.server.wm.AnimationSpecProto.ALPHA;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
 
+import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
@@ -178,6 +179,7 @@
         mSurfaceAnimatorStarter = surfaceAnimatorStarter;
     }
 
+    @NonNull
     WindowContainer<?> getHost() {
         return mHost;
     }
@@ -199,13 +201,6 @@
             try {
                 final SurfaceControl ctl = makeDimLayer();
                 mDimState = new DimState(ctl);
-                /**
-                 * See documentation on {@link #dimAbove} to understand lifecycle management of
-                 * Dim's via state resetting for Dim's with containers.
-                 */
-                if (container == null) {
-                    mDimState.mDontReset = true;
-                }
             } catch (Surface.OutOfResourcesException e) {
                 Log.w(TAG, "OutOfResourcesException creating dim surface");
             }
@@ -241,7 +236,7 @@
      * @param container The container which to dim above. Should be a child of our host.
      * @param alpha     The alpha at which to Dim.
      */
-    void dimAbove(WindowContainer container, float alpha) {
+    void dimAbove(@NonNull WindowContainer container, float alpha) {
         dim(container, 1, alpha, 0);
     }
 
@@ -253,7 +248,7 @@
      * @param blurRadius The amount of blur added to the Dim.
      */
 
-    void dimBelow(WindowContainer container, float alpha, int blurRadius) {
+    void dimBelow(@NonNull WindowContainer container, float alpha, int blurRadius) {
         dim(container, -1, alpha, blurRadius);
     }
 
@@ -316,7 +311,12 @@
             if (!mDimState.isVisible) {
                 mDimState.isVisible = true;
                 t.show(mDimState.mDimLayer);
-                startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+                // Skip enter animation while starting window is on top of its activity
+                final WindowState ws = mLastRequestedDimContainer.asWindowState();
+                if (ws == null || ws.mActivityRecord == null
+                        || ws.mActivityRecord.mStartingData == null) {
+                    startDimEnter(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
+                }
             }
             return true;
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2e51fe41..daa73db 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -743,9 +743,6 @@
     /** Set of activities in foreground size compat mode. */
     private Set<ActivityRecord> mActiveSizeCompatActivities = new ArraySet<>();
 
-    // Used in updating the display size
-    private Point mTmpDisplaySize = new Point();
-
     // Used in updating override configurations
     private final Configuration mTempConfig = new Configuration();
 
@@ -4797,25 +4794,6 @@
         }, false /* traverseTopToBottom */);
     }
 
-    /**
-     * Starts the Keyguard exit animation on all windows that don't belong to an app token.
-     */
-    void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade,
-            boolean subtle) {
-        final WindowManagerPolicy policy = mWmService.mPolicy;
-        forAllWindows(w -> {
-            if (w.mActivityRecord == null && w.canBeHiddenByKeyguard()
-                    && w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
-                w.startAnimation(policy.createHiddenByKeyguardExit(
-                        onWallpaper, goingToShade, subtle));
-            }
-        }, true /* traverseTopToBottom */);
-        for (int i = mShellRoots.size() - 1; i >= 0; --i) {
-            mShellRoots.valueAt(i).startAnimation(policy.createHiddenByKeyguardExit(
-                    onWallpaper, goingToShade, subtle));
-        }
-    }
-
     /** @return {@code true} if there is window to wait before enabling the screen. */
     boolean shouldWaitForSystemDecorWindowsOnBoot() {
         if (!isDefaultDisplay && !supportsSystemDecorations()) {
@@ -6519,10 +6497,11 @@
     }
 
     /**
-     * @return whether the physical display has a fixed orientation and cannot be rotated.
+     * @return whether the physical display orientation should change when its content rotates to
+     *   match the orientation of the content.
      */
-    boolean isDisplayOrientationFixed() {
-        return (mDisplayInfo.flags & Display.FLAG_ROTATES_WITH_CONTENT) == 0;
+    boolean shouldRotateWithContent() {
+        return (mDisplayInfo.flags & Display.FLAG_ROTATES_WITH_CONTENT) != 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1871cf6..707b779 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
 import static android.view.Display.TYPE_INTERNAL;
 import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE;
 import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS;
@@ -1201,8 +1202,8 @@
                 throw new IllegalArgumentException("IME insets must be provided by a window.");
             }
 
-            if (mNavigationBar != null && navigationBarPosition(displayFrames.mRotation)
-                    == NAV_BAR_BOTTOM) {
+            if (!ENABLE_HIDE_IME_CAPTION_BAR && mNavigationBar != null
+                    && navigationBarPosition(displayFrames.mRotation) == NAV_BAR_BOTTOM) {
                 // In gesture navigation, nav bar frame is larger than frame to calculate insets.
                 // IME should not provide frame which is smaller than the nav bar frame. Otherwise,
                 // nav bar might be overlapped with the content of the client when IME is shown.
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 9ef25b6..d461d1e 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -435,7 +435,7 @@
                 PackageManager.FEATURE_LEANBACK);
         mDefaultFixedToUserRotation =
                 (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()
-                        || mDisplayContent.isDisplayOrientationFixed())
+                        || !mDisplayContent.shouldRotateWithContent())
                 // For debug purposes the next line turns this feature off with:
                 // $ adb shell setprop config.override_forced_orient true
                 // $ adb shell wm size reset
@@ -948,7 +948,7 @@
         mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
                 userRotation);
         if (changed) {
-            mService.updateRotation(true /* alwaysSendConfiguration */,
+            mService.updateRotation(false /* alwaysSendConfiguration */,
                     false /* forceRelayout */);
         }
     }
@@ -2127,7 +2127,7 @@
         @Override
         public void onChange(boolean selfChange) {
             if (updateSettings()) {
-                mService.updateRotation(true /* alwaysSendConfiguration */,
+                mService.updateRotation(false /* alwaysSendConfiguration */,
                         false /* forceRelayout */);
             }
         }
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 2fb9869..6b33746 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -68,19 +68,15 @@
     }
 
     /**
-     * @see DisplayWindowPolicyController#canContainActivities(List, int)
+     * @see DisplayWindowPolicyController#canContainActivities
      */
     public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
             @WindowConfiguration.WindowingMode int windowingMode) {
         if (mDisplayWindowPolicyController == null) {
-            for (int i = activities.size() - 1; i >= 0; i--) {
-                final ActivityInfo aInfo = activities.get(i);
-                if (aInfo.requiredDisplayCategory != null) {
-                    Slog.e(TAG,
-                            String.format("Activity with requiredDisplayCategory='%s' cannot be"
-                                            + " displayed on display %d because that display does"
-                                            + " not have a matching category",
-                                    aInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
+            for (int i = 0; i < activities.size(); ++i) {
+                // Missing controller means that this display has no categories for activity launch
+                // restriction.
+                if (hasDisplayCategory(activities.get(i))) {
                     return false;
                 }
             }
@@ -90,26 +86,31 @@
     }
 
     /**
-     * @see DisplayWindowPolicyController#canActivityBeLaunched(ActivityInfo, int, int, boolean)
+     * @see DisplayWindowPolicyController#canActivityBeLaunched
      */
     public boolean canActivityBeLaunched(ActivityInfo activityInfo,
             Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
             int launchingFromDisplayId, boolean isNewTask) {
         if (mDisplayWindowPolicyController == null) {
-            if (activityInfo.requiredDisplayCategory != null) {
-                Slog.e(TAG,
-                        String.format("Activity with requiredDisplayCategory='%s' cannot be"
-                                + " launched on display %d because that display does"
-                                + " not have a matching category",
-                                activityInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
-                return false;
-            }
-            return true;
+            // Missing controller means that this display has no categories for activity launch
+            // restriction.
+            return !hasDisplayCategory(activityInfo);
         }
         return mDisplayWindowPolicyController.canActivityBeLaunched(activityInfo, intent,
             windowingMode, launchingFromDisplayId, isNewTask);
     }
 
+    private boolean hasDisplayCategory(ActivityInfo aInfo) {
+        if (aInfo.requiredDisplayCategory != null) {
+            Slog.d(TAG,
+                    String.format("Checking activity launch with requiredDisplayCategory='%s' on"
+                                    + " display %d, which doesn't have a matching category.",
+                            aInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
+            return true;
+        }
+        return false;
+    }
+
     /**
      * @see DisplayWindowPolicyController#keepActivityOnWindowFlagsChanged(ActivityInfo, int, int)
      */
@@ -199,7 +200,6 @@
         return mDisplayWindowPolicyController.isEnteringPipAllowed(uid);
     }
 
-
     void dump(String prefix, PrintWriter pw) {
         if (mDisplayWindowPolicyController != null) {
             pw.println();
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 8c1d8fa..1a319ad 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -423,7 +423,7 @@
 
         final TransitionController tc = mRootWindowContainer.mTransitionController;
 
-        final boolean occluded = isDisplayOccluded(displayId);
+        final boolean occluded = getDisplayState(displayId).mOccluded;
         final boolean performTransition = isKeyguardLocked(displayId);
         final boolean executeTransition = performTransition && !tc.isCollecting();
 
@@ -500,15 +500,6 @@
         }
     }
 
-    /**
-     * Returns {@code true} if the top activity on the display can occlude keyguard or the device
-     * is dreaming. Note that this method may return {@code true} even if the keyguard is disabled
-     * or not showing.
-     */
-    boolean isDisplayOccluded(int displayId) {
-        return getDisplayState(displayId).mOccluded;
-    }
-
     ActivityRecord getTopOccludingActivity(int displayId) {
         return getDisplayState(displayId).mTopOccludesActivity;
     }
@@ -601,6 +592,11 @@
         private boolean mAodShowing;
         private boolean mKeyguardGoingAway;
         private boolean mDismissalRequested;
+
+        /**
+         * True if the top activity on the display can occlude keyguard or the device is dreaming.
+         * Note that this can be true even if the keyguard is disabled or not showing.
+         */
         private boolean mOccluded;
         private boolean mShowingDream;
 
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index 9e3a611..45cf10b 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -80,10 +80,10 @@
 
     // Whether per-app user aspect ratio override settings is enabled
     private static final String KEY_ENABLE_USER_ASPECT_RATIO_SETTINGS =
-            "enable_app_compat_user_aspect_ratio_settings";
+            "enable_app_compat_aspect_ratio_user_settings";
 
     // TODO(b/288142656): Enable user aspect ratio settings by default.
-    private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false;
+    private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = true;
 
     // Whether per-app fullscreen user aspect ratio override option is enabled
     private static final String KEY_ENABLE_USER_ASPECT_RATIO_FULLSCREEN =
@@ -880,6 +880,58 @@
                         false /* forTabletopMode */);
     }
 
+    /**
+     * Overrides persistent horizontal position of the letterboxed app window when horizontal
+     * reachability is enabled.
+     */
+    void setPersistentLetterboxPositionForHorizontalReachability(boolean forBookMode,
+            @LetterboxHorizontalReachabilityPosition int position) {
+        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
+                forBookMode, position);
+    }
+
+    /**
+     * Overrides persistent vertical position of the letterboxed app window when vertical
+     * reachability is enabled.
+     */
+    void setPersistentLetterboxPositionForVerticalReachability(boolean forTabletopMode,
+            @LetterboxVerticalReachabilityPosition int position) {
+        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
+                forTabletopMode, position);
+    }
+
+    /**
+     * Resets persistent horizontal position of the letterboxed app window when horizontal
+     * reachability
+     * is enabled to default position.
+     */
+    void resetPersistentLetterboxPositionForHorizontalReachability() {
+        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
+                false /* forBookMode */,
+                readLetterboxHorizontalReachabilityPositionFromConfig(mContext,
+                        false /* forBookMode */));
+        mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
+                true /* forBookMode */,
+                readLetterboxHorizontalReachabilityPositionFromConfig(mContext,
+                        true /* forBookMode */));
+    }
+
+    /**
+     * Resets persistent vertical position of the letterboxed app window when vertical reachability
+     * is
+     * enabled to default position.
+     */
+    void resetPersistentLetterboxPositionForVerticalReachability() {
+        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
+                false /* forTabletopMode */,
+                readLetterboxVerticalReachabilityPositionFromConfig(mContext,
+                        false /* forTabletopMode */));
+        mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
+                true /* forTabletopMode */,
+                readLetterboxVerticalReachabilityPositionFromConfig(mContext,
+                        true /* forTabletopMode */));
+    }
+
     @LetterboxHorizontalReachabilityPosition
     private static int readLetterboxHorizontalReachabilityPositionFromConfig(Context context,
             boolean forBookMode) {
diff --git a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
index e646f14..106e142 100644
--- a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
+++ b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.Slog;
 import android.view.IDisplayChangeWindowCallback;
 import android.window.DisplayAreaInfo;
@@ -40,6 +41,7 @@
 public class RemoteDisplayChangeController {
 
     private static final String TAG = "RemoteDisplayChangeController";
+    private static final String REMOTE_DISPLAY_CHANGE_TRACE_TAG = "RemoteDisplayChange";
 
     private static final int REMOTE_DISPLAY_CHANGE_TIMEOUT_MS = 800;
 
@@ -82,6 +84,10 @@
         }
         mCallbacks.add(callback);
 
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+            Trace.beginAsyncSection(REMOTE_DISPLAY_CHANGE_TRACE_TAG, callback.hashCode());
+        }
+
         if (newDisplayAreaInfo != null) {
             ProtoLog.v(WM_DEBUG_CONFIGURATION,
                     "Starting remote display change: "
@@ -122,6 +128,10 @@
                     mCallbacks.clear();
                 }
                 callback.onContinueRemoteDisplayChange(null /* transaction */);
+
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                    Trace.endAsyncSection(REMOTE_DISPLAY_CHANGE_TRACE_TAG, callback.hashCode());
+                }
             }
         }
     }
@@ -137,13 +147,23 @@
             for (int i = 0; i < idx; ++i) {
                 // Expect remote callbacks in order. If they don't come in order, then force
                 // ordering by continuing everything up until this one with empty transactions.
-                mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
+                ContinueRemoteDisplayChangeCallback currentCallback = mCallbacks.get(i);
+                currentCallback.onContinueRemoteDisplayChange(null /* transaction */);
+
+                if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                    Trace.endAsyncSection(REMOTE_DISPLAY_CHANGE_TRACE_TAG,
+                            currentCallback.hashCode());
+                }
             }
             mCallbacks.subList(0, idx + 1).clear();
             if (mCallbacks.isEmpty()) {
                 mService.mH.removeCallbacks(mTimeoutRunnable);
             }
             callback.onContinueRemoteDisplayChange(transaction);
+
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                Trace.endAsyncSection(REMOTE_DISPLAY_CHANGE_TRACE_TAG, callback.hashCode());
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6b4cc25..2fdfec0 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -258,10 +258,6 @@
      */
     final SparseArray<SleepToken> mSleepTokens = new SparseArray<>();
 
-    // The default minimal size that will be used if the activity doesn't specify its minimal size.
-    // It will be calculated when the default display gets added.
-    int mDefaultMinSizeOfResizeableTaskDp = -1;
-
     // Whether tasks have moved and we need to rank the tasks before next OOM scoring
     private boolean mTaskLayersChanged = true;
     private int mTmpTaskLayerRank;
@@ -1608,6 +1604,19 @@
     }
 
     /**
+     * Check if the display is valid for primary home activity.
+     *
+     * @param displayId The target display ID
+     * @return {@code true} if allowed to launch, {@code false} otherwise.
+     */
+    boolean shouldPlacePrimaryHomeOnDisplay(int displayId) {
+        // No restrictions to default display, vr 2d display or main display for visible users.
+        return displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
+                && (displayId == mService.mVr2dDisplayId
+                || mWmService.shouldPlacePrimaryHomeOnDisplay(displayId)));
+    }
+
+    /**
      * Check if the display area is valid for secondary home activity.
      *
      * @param taskDisplayArea The target display area.
@@ -1680,10 +1689,7 @@
 
         final int displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId()
                 : INVALID_DISPLAY;
-        if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
-                && (displayId == mService.mVr2dDisplayId
-                || mWmService.shouldPlacePrimaryHomeOnDisplay(displayId)))) {
-            // No restrictions to default display, vr 2d display or main display for visible users.
+        if (shouldPlacePrimaryHomeOnDisplay(displayId)) {
             return true;
         }
 
@@ -2699,7 +2705,7 @@
             // transition exists, so this affects only when no lock screen is set. Otherwise
             // keyguard going away animation will be played.
             // See also AppTransitionController#getTransitCompatType for more details.
-            if ((!mTaskSupervisor.getKeyguardController().isDisplayOccluded(display.mDisplayId)
+            if ((!mTaskSupervisor.getKeyguardController().isKeyguardOccluded(display.mDisplayId)
                     && token.mTag.equals(KEYGUARD_SLEEP_TOKEN_TAG))
                     || token.mTag.equals(DISPLAY_OFF_SLEEP_TOKEN_TAG)) {
                 display.mSkipAppTransitionAnimation = true;
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index a23547e..2d281c4 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -76,7 +76,7 @@
      * This starting window should be removed after applying the start transaction of transition,
      * which ensures the app window has shown.
      */
-    @AfterTransaction int mRemoveAfterTransaction;
+    @AfterTransaction int mRemoveAfterTransaction = AFTER_TRANSACTION_IDLE;
 
     /** Whether to prepare the removal animation. */
     boolean mPrepareRemoveAnimation;
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 0bb773a..a55c232 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -40,6 +40,7 @@
 import android.content.pm.ApplicationInfo;
 import android.os.UserHandle;
 import android.util.Slog;
+import android.window.ITaskOrganizer;
 import android.window.SplashScreenView;
 import android.window.TaskSnapshot;
 
@@ -79,12 +80,13 @@
     }
 
     StartingSurface createSplashScreenStartingSurface(ActivityRecord activity, int theme) {
-
         synchronized (mService.mGlobalLock) {
             final Task task = activity.getTask();
-            if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(
-                    task, activity, theme, null /* taskSnapshot */)) {
-                return new StartingSurface(task);
+            final TaskOrganizerController controller =
+                    mService.mAtmService.mTaskOrganizerController;
+            if (task != null && controller.addStartingWindow(task, activity, theme,
+                    null /* taskSnapshot */)) {
+                return new StartingSurface(task, controller.getTaskOrganizer());
             }
         }
         return null;
@@ -166,9 +168,12 @@
                 activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
                         activity, false /* checkOpening */);
             }
-                mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
-                        activity, 0 /* launchTheme */, taskSnapshot);
-            return new StartingSurface(task);
+            final TaskOrganizerController controller =
+                    mService.mAtmService.mTaskOrganizerController;
+            if (controller.addStartingWindow(task, activity, 0 /* launchTheme */, taskSnapshot)) {
+                return new StartingSurface(task, controller.getTaskOrganizer());
+            }
+            return null;
         }
     }
 
@@ -256,9 +261,12 @@
 
     final class StartingSurface {
         private final Task mTask;
+        // The task organizer which hold the client side reference of this surface.
+        final ITaskOrganizer mTaskOrganizer;
 
-        StartingSurface(Task task) {
+        StartingSurface(Task task, ITaskOrganizer taskOrganizer) {
             mTask = task;
+            mTaskOrganizer = taskOrganizer;
         }
 
         /**
@@ -268,7 +276,8 @@
          */
         public void remove(boolean animate) {
             synchronized (mService.mGlobalLock) {
-                mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask, animate);
+                mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask,
+                        mTaskOrganizer, animate);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f9bbc68..21526e7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2815,7 +2815,7 @@
         final WindowManager.LayoutParams attrs = win.mAttrs;
         visibleFrame.set(win.getFrame());
         visibleFrame.inset(win.getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                visibleFrame, attrs.type, win.getWindowingMode(), attrs.softInputMode,
+                visibleFrame, attrs.type, win.getActivityType(), attrs.softInputMode,
                 attrs.flags));
         out.union(visibleFrame);
     }
@@ -3543,11 +3543,6 @@
                 ? null : new PictureInPictureParams(top.pictureInPictureArgs);
     }
 
-    private boolean shouldDockBigOverlays() {
-        final ActivityRecord topMostActivity = getTopMostActivity();
-        return topMostActivity != null && topMostActivity.shouldDockBigOverlays;
-    }
-
     Rect getDisplayCutoutInsets() {
         if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null;
         final WindowState w = getTopVisibleAppMainWindow();
@@ -3579,7 +3574,7 @@
                 && activity.info != info.taskInfo.topActivityInfo
                 ? activity.info : null;
         info.isKeyguardOccluded =
-            mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY);
+                mAtmService.mKeyguardController.isKeyguardOccluded(info.taskInfo.displayId);
 
         info.startingWindowTypeParameter = activity.mStartingData != null
                 ? activity.mStartingData.mTypeParams
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index ad46770..4e7a9bd 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -118,12 +118,14 @@
             root = activity;
         }
 
-        if (root == null) {
+        if (root == null && phase != PHASE_DISPLAY) {
             // There is a case that can lead us here. The caller is moving the top activity that is
             // in a task that has multiple activities to PIP mode. For that the caller is creating a
             // new task to host the activity so that we only move the top activity to PIP mode and
             // keep other activities in the previous task. There is no point to apply the launch
             // logic in this case.
+            // However, for PHASE_DISPLAY the root may be null, but we still want to get a hint of
+            // what the suggested launch display area would be.
             return RESULT_SKIP;
         }
 
@@ -395,8 +397,9 @@
     }
 
     private TaskDisplayArea getPreferredLaunchTaskDisplayArea(@Nullable Task task,
-            @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams,
-            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+            @Nullable ActivityOptions options, @Nullable ActivityRecord source,
+            @Nullable LaunchParams currentParams, @Nullable ActivityRecord activityRecord,
+            @Nullable Request request) {
         TaskDisplayArea taskDisplayArea = null;
 
         final WindowContainerToken optionLaunchTaskDisplayAreaToken = options != null
@@ -438,8 +441,7 @@
 
         // If the source activity is a no-display activity, pass on the launch display area token
         // from source activity as currently preferred.
-        if (taskDisplayArea == null && source != null
-                && source.noDisplay) {
+        if (taskDisplayArea == null && source != null && source.noDisplay) {
             taskDisplayArea = source.mHandoverTaskDisplayArea;
             if (taskDisplayArea != null) {
                 if (DEBUG) appendLog("display-area-from-no-display-source=" + taskDisplayArea);
@@ -478,21 +480,24 @@
             }
         }
 
-        if (taskDisplayArea == null) {
+        if (taskDisplayArea == null && currentParams != null) {
             taskDisplayArea = currentParams.mPreferredTaskDisplayArea;
+            if (DEBUG) appendLog("display-area-from-current-params=" + taskDisplayArea);
         }
 
         // Re-route to default display if the device didn't declare support for multi-display
         if (taskDisplayArea != null && !mSupervisor.mService.mSupportsMultiDisplay
                 && taskDisplayArea.getDisplayId() != DEFAULT_DISPLAY) {
             taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+            if (DEBUG) appendLog("display-area-from-no-multidisplay=" + taskDisplayArea);
         }
 
         // Re-route to default display if the home activity doesn't support multi-display
-        if (taskDisplayArea != null && activityRecord.isActivityTypeHome()
+        if (taskDisplayArea != null && activityRecord != null && activityRecord.isActivityTypeHome()
                 && !mSupervisor.mRootWindowContainer.canStartHomeOnDisplayArea(activityRecord.info,
                         taskDisplayArea, false /* allowInstrumenting */)) {
             taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+            if (DEBUG) appendLog("display-area-from-home=" + taskDisplayArea);
         }
 
         return (taskDisplayArea != null)
@@ -516,34 +521,56 @@
      * @return {@link TaskDisplayArea} to house the task
      */
     private TaskDisplayArea getFallbackDisplayAreaForActivity(
-            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
+            @Nullable ActivityRecord activityRecord, @Nullable Request request) {
+        if (activityRecord != null) {
+            WindowProcessController controllerFromLaunchingRecord =
+                    mSupervisor.mService.getProcessController(
+                            activityRecord.launchedFromPid, activityRecord.launchedFromUid);
+            if (controllerFromLaunchingRecord != null) {
+                final TaskDisplayArea taskDisplayAreaForLaunchingRecord =
+                        controllerFromLaunchingRecord.getTopActivityDisplayArea();
+                if (taskDisplayAreaForLaunchingRecord != null) {
+                    if (DEBUG) {
+                        appendLog("display-area-for-launching-record="
+                                + taskDisplayAreaForLaunchingRecord);
+                    }
+                    return taskDisplayAreaForLaunchingRecord;
+                }
+            }
 
-        WindowProcessController controllerFromLaunchingRecord = mSupervisor.mService
-                .getProcessController(activityRecord.launchedFromPid,
-                        activityRecord.launchedFromUid);
-        final TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
-                ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
-        if (displayAreaForLaunchingRecord != null) {
-            return displayAreaForLaunchingRecord;
+            WindowProcessController controllerFromProcess =
+                    mSupervisor.mService.getProcessController(
+                            activityRecord.getProcessName(), activityRecord.getUid());
+            if (controllerFromProcess != null) {
+                final TaskDisplayArea displayAreaForRecord =
+                        controllerFromProcess.getTopActivityDisplayArea();
+                if (displayAreaForRecord != null) {
+                    if (DEBUG) appendLog("display-area-for-record=" + displayAreaForRecord);
+                    return displayAreaForRecord;
+                }
+            }
         }
 
-        WindowProcessController controllerFromProcess = mSupervisor.mService.getProcessController(
-                activityRecord.getProcessName(), activityRecord.getUid());
-        final TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
-                : controllerFromProcess.getTopActivityDisplayArea();
-        if (displayAreaForRecord != null) {
-            return displayAreaForRecord;
+        if (request != null) {
+            WindowProcessController controllerFromRequest =
+                    mSupervisor.mService.getProcessController(
+                            request.realCallingPid, request.realCallingUid);
+            if (controllerFromRequest != null) {
+                final TaskDisplayArea displayAreaFromSourceProcess =
+                            controllerFromRequest.getTopActivityDisplayArea();
+                if (displayAreaFromSourceProcess != null) {
+                    if (DEBUG) {
+                        appendLog("display-area-source-process=" + displayAreaFromSourceProcess);
+                    }
+                    return displayAreaFromSourceProcess;
+                }
+            }
         }
 
-        WindowProcessController controllerFromRequest = request == null ? null : mSupervisor
-                .mService.getProcessController(request.realCallingPid, request.realCallingUid);
-        final TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
-                : controllerFromRequest.getTopActivityDisplayArea();
-        if (displayAreaFromSourceProcess != null) {
-            return displayAreaFromSourceProcess;
-        }
-
-        return mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+        final TaskDisplayArea defaultTaskDisplayArea =
+                mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
+        if (DEBUG) appendLog("display-area-from-default-fallback=" + defaultTaskDisplayArea);
+        return defaultTaskDisplayArea;
     }
 
     private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
@@ -559,7 +586,7 @@
             return false;
         }
 
-        final int sourceWindowingMode = source.getWindowingMode();
+        final int sourceWindowingMode = source.getTask().getWindowingMode();
         if (sourceWindowingMode != WINDOWING_MODE_FULLSCREEN
                 && sourceWindowingMode != WINDOWING_MODE_FREEFORM) {
             return false;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 3d01001..41e49b9 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -652,7 +652,7 @@
         if (rootTask == null || activity.mStartingData == null) {
             return false;
         }
-        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        final ITaskOrganizer lastOrganizer = getTaskOrganizer();
         if (lastOrganizer == null) {
             return false;
         }
@@ -672,12 +672,13 @@
         return true;
     }
 
-    void removeStartingWindow(Task task, boolean prepareAnimation) {
+    void removeStartingWindow(Task task, ITaskOrganizer taskOrganizer, boolean prepareAnimation) {
         final Task rootTask = task.getRootTask();
         if (rootTask == null) {
             return;
         }
-        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        final ITaskOrganizer lastOrganizer = taskOrganizer != null ? taskOrganizer
+                : getTaskOrganizer();
         if (lastOrganizer == null) {
             return;
         }
@@ -771,12 +772,13 @@
         }
     }
 
-    boolean copySplashScreenView(Task task) {
+    boolean copySplashScreenView(Task task, ITaskOrganizer taskOrganizer) {
         final Task rootTask = task.getRootTask();
         if (rootTask == null) {
             return false;
         }
-        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        final ITaskOrganizer lastOrganizer = taskOrganizer != null ? taskOrganizer
+                : getTaskOrganizer();
         if (lastOrganizer == null) {
             return false;
         }
@@ -799,12 +801,12 @@
      * @see com.android.wm.shell.ShellTaskOrganizer#onAppSplashScreenViewRemoved(int)
      * @see SplashScreenView#remove()
      */
-    public void onAppSplashScreenViewRemoved(Task task) {
+    public void onAppSplashScreenViewRemoved(Task task, ITaskOrganizer organizer) {
         final Task rootTask = task.getRootTask();
         if (rootTask == null) {
             return;
         }
-        final ITaskOrganizer lastOrganizer = mTaskOrganizers.peekLast();
+        final ITaskOrganizer lastOrganizer = organizer != null ? organizer : getTaskOrganizer();
         if (lastOrganizer == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index e9af42b..a6c6491 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -440,10 +440,11 @@
     boolean canApplyDim(@NonNull Task task) {
         if (mTransientLaunches == null) return true;
         final Dimmer dimmer = task.getDimmer();
-        final WindowContainer<?> dimmerHost = dimmer != null ? dimmer.getHost() : null;
-        if (dimmerHost == null) return false;
-        if (isInTransientHide(dimmerHost)) {
-            // The layer of dimmer is inside transient-hide task, then allow to dim.
+        if (dimmer == null) {
+            return false;
+        }
+        if (dimmer.getHost().asTask() != null) {
+            // Always allow to dim if the host only affects its task.
             return true;
         }
         // The dimmer host of a translucent task can be a display, then it is not in transient-hide.
@@ -1127,6 +1128,9 @@
                         // though, notify the controller to prevent degenerate cases.
                         if (!r.isVisibleRequested()) {
                             mController.mValidateCommitVis.add(r);
+                        } else {
+                            // Make sure onAppTransitionFinished can be notified.
+                            mParticipants.add(r);
                         }
                         return;
                     }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dae61da..4a0f44b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1135,13 +1135,6 @@
         return parent != null && parent.isAttached();
     }
 
-    void setWaitingForDrawnIfResizingChanged() {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer wc = mChildren.get(i);
-            wc.setWaitingForDrawnIfResizingChanged();
-        }
-    }
-
     void onResize() {
         if (mControllableInsetProvider != null) {
             mControllableInsetProvider.onWindowContainerBoundsChanged();
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index ceebb27..bfe0553 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -911,6 +911,70 @@
         return 0;
     }
 
+    private int runSetPersistentLetterboxPositionForHorizontalReachability(PrintWriter pw)
+            throws RemoteException {
+        @LetterboxHorizontalReachabilityPosition final int position;
+        try {
+            String arg = getNextArgRequired();
+            switch (arg) {
+                case "left":
+                    position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
+                    break;
+                case "center":
+                    position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
+                    break;
+                case "right":
+                    position = LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
+                    break;
+                default:
+                    getErrPrintWriter().println(
+                            "Error: 'left', 'center' or 'right' are expected as an argument");
+                    return -1;
+            }
+        } catch (IllegalArgumentException e) {
+            getErrPrintWriter().println(
+                    "Error: 'left', 'center' or 'right' are expected as an argument" + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setPersistentLetterboxPositionForHorizontalReachability(
+                    false /* IsInBookMode */, position);
+        }
+        return 0;
+    }
+
+    private int runSetPersistentLetterboxPositionForVerticalReachability(PrintWriter pw)
+            throws RemoteException {
+        @LetterboxVerticalReachabilityPosition final int position;
+        try {
+            String arg = getNextArgRequired();
+            switch (arg) {
+                case "top":
+                    position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
+                    break;
+                case "center":
+                    position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
+                    break;
+                case "bottom":
+                    position = LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
+                    break;
+                default:
+                    getErrPrintWriter().println(
+                            "Error: 'top', 'center' or 'bottom' are expected as an argument");
+                    return -1;
+            }
+        } catch (IllegalArgumentException e) {
+            getErrPrintWriter().println(
+                    "Error: 'top', 'center' or 'bottom' are expected as an argument" + e);
+            return -1;
+        }
+        synchronized (mInternal.mGlobalLock) {
+            mLetterboxConfiguration.setPersistentLetterboxPositionForVerticalReachability(
+                    false /* forTabletopMode */, position);
+        }
+        return 0;
+    }
+
     private int runSetBooleanFlag(PrintWriter pw, Consumer<Boolean> setter)
             throws RemoteException {
         String arg = getNextArg();
@@ -994,6 +1058,12 @@
                 case "--defaultPositionForVerticalReachability":
                     runSetLetterboxDefaultPositionForVerticalReachability(pw);
                     break;
+                case "--persistentPositionForHorizontalReachability":
+                    runSetPersistentLetterboxPositionForHorizontalReachability(pw);
+                    break;
+                case "--persistentPositionForVerticalReachability":
+                    runSetPersistentLetterboxPositionForVerticalReachability(pw);
+                    break;
                 case "--isEducationEnabled":
                     runSetBooleanFlag(pw, mLetterboxConfiguration::setIsEducationEnabled);
                     break;
@@ -1080,6 +1150,14 @@
                     case "defaultPositionForVerticalReachability":
                         mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
                         break;
+                    case "persistentPositionForHorizontalReachability":
+                        mLetterboxConfiguration
+                                .resetPersistentLetterboxPositionForHorizontalReachability();
+                        break;
+                    case "persistentPositionForVerticalReachability":
+                        mLetterboxConfiguration
+                                .resetPersistentLetterboxPositionForVerticalReachability();
+                        break;
                     case "isEducationEnabled":
                         mLetterboxConfiguration.resetIsEducationEnabled();
                         break;
@@ -1206,6 +1284,8 @@
             mLetterboxConfiguration.resetEnabledAutomaticReachabilityInBookMode();
             mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability();
             mLetterboxConfiguration.resetDefaultPositionForVerticalReachability();
+            mLetterboxConfiguration.resetPersistentLetterboxPositionForHorizontalReachability();
+            mLetterboxConfiguration.resetPersistentLetterboxPositionForVerticalReachability();
             mLetterboxConfiguration.resetIsEducationEnabled();
             mLetterboxConfiguration.resetIsSplitScreenAspectRatioForUnresizableAppsEnabled();
             mLetterboxConfiguration.resetIsDisplayAspectRatioEnabledForFixedOrientationLetterbox();
@@ -1233,6 +1313,12 @@
             pw.println("Vertical position multiplier (tabletop mode): "
                     + mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier(
                             true /* isInTabletopMode */));
+            pw.println("Horizontal position multiplier for reachability: "
+                    + mLetterboxConfiguration.getHorizontalMultiplierForReachability(
+                            false /* isInBookMode */));
+            pw.println("Vertical position multiplier for reachability: "
+                    + mLetterboxConfiguration.getVerticalMultiplierForReachability(
+                            false /* isInTabletopMode */));
             pw.println("Aspect ratio: "
                     + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio());
             pw.println("Default min aspect ratio for unresizable apps: "
@@ -1472,6 +1558,12 @@
         pw.println("      --defaultPositionForVerticalReachability [top|center|bottom]");
         pw.println("        Default position of app window when vertical reachability is.");
         pw.println("        enabled.");
+        pw.println("      --persistentPositionForHorizontalReachability [left|center|right]");
+        pw.println("        Persistent position of app window when horizontal reachability is.");
+        pw.println("        enabled.");
+        pw.println("      --persistentPositionForVerticalReachability [top|center|bottom]");
+        pw.println("        Persistent position of app window when vertical reachability is.");
+        pw.println("        enabled.");
         pw.println("      --isEducationEnabled [true|1|false|0]");
         pw.println("        Whether education is allowed for letterboxed fullscreen apps.");
         pw.println("      --isSplitScreenAspectRatioForUnresizableAppsEnabled [true|1|false|0]");
@@ -1493,8 +1585,10 @@
         pw.println("      |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha");
         pw.println("      |horizontalPositionMultiplier|verticalPositionMultiplier");
         pw.println("      |isHorizontalReachabilityEnabled|isVerticalReachabilityEnabled");
-        pw.println("      |isEducationEnabled||defaultPositionMultiplierForHorizontalReachability");
+        pw.println("      |isEducationEnabled|defaultPositionMultiplierForHorizontalReachability");
         pw.println("      |isTranslucentLetterboxingEnabled|isUserAppAspectRatioSettingsEnabled");
+        pw.println("      |persistentPositionMultiplierForHorizontalReachability");
+        pw.println("      |persistentPositionMultiplierForVerticalReachability");
         pw.println("      |defaultPositionMultiplierForVerticalReachability]");
         pw.println("    Resets overrides to default values for specified properties separated");
         pw.println("    by space, e.g. 'reset-letterbox-style aspectRatio cornerRadius'.");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a172d99..b12cc0b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1717,29 +1717,6 @@
     }
 
     /**
-     * This is a form of rectangle "difference". It cut off each dimension of rect by the amount
-     * that toRemove is "pushing into" it from the outside. Any dimension that fully contains
-     * toRemove won't change.
-     */
-    private void cutRect(Rect rect, Rect toRemove) {
-        if (toRemove.isEmpty()) return;
-        if (toRemove.top < rect.bottom && toRemove.bottom > rect.top) {
-            if (toRemove.right >= rect.right && toRemove.left >= rect.left) {
-                rect.right = toRemove.left;
-            } else if (toRemove.left <= rect.left && toRemove.right <= rect.right) {
-                rect.left = toRemove.right;
-            }
-        }
-        if (toRemove.left < rect.right && toRemove.right > rect.left) {
-            if (toRemove.bottom >= rect.bottom && toRemove.top >= rect.top) {
-                rect.bottom = toRemove.top;
-            } else if (toRemove.top <= rect.top && toRemove.bottom <= rect.bottom) {
-                rect.top = toRemove.bottom;
-            }
-        }
-    }
-
-    /**
      * Retrieves the visible bounds of the window.
      * @param bounds The rect which gets the bounds.
      */
@@ -1759,7 +1736,7 @@
 
         bounds.set(mWindowFrames.mFrame);
         bounds.inset(getInsetsStateWithVisibilityOverride().calculateVisibleInsets(
-                bounds, mAttrs.type, getWindowingMode(), mAttrs.softInputMode, mAttrs.flags));
+                bounds, mAttrs.type, getActivityType(), mAttrs.softInputMode, mAttrs.flags));
         if (intersectWithRootTaskBounds) {
             bounds.intersect(mTmpRect);
         }
@@ -3965,14 +3942,6 @@
         return mDragResizing != computeDragResizing();
     }
 
-    @Override
-    void setWaitingForDrawnIfResizingChanged() {
-        if (isDragResizeChanged()) {
-            mWmService.mRoot.mWaitingForDrawn.add(this);
-        }
-        super.setWaitingForDrawnIfResizingChanged();
-    }
-
     /**
      * Resets the state whether we reported a drag resize change to the app.
      */
@@ -5524,10 +5493,6 @@
         outRegion.translate(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top);
     }
 
-    boolean hasTapExcludeRegion() {
-        return !mTapExcludeRegion.isEmpty();
-    }
-
     boolean isImeLayeringTarget() {
         return getDisplayContent().getImeTarget(IME_TARGET_LAYERING) == this;
     }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 31afcbf..e434f29 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -519,7 +518,8 @@
         for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) {
             final ActivityRecord r =
                     mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord();
-            if (r != null && r.isInTransition()) {
+            // Only care about the transition at Activity/Task level.
+            if (r != null && r.inTransitionSelfOrParent() && !r.mDisplayContent.inTransition()) {
                 return true;
             }
         }
@@ -745,17 +745,6 @@
         return this;
     }
 
-    /**
-     * Return whether windows from this token can layer above the
-     * system bars, or in other words extend outside of the "Decor Frame"
-     */
-    boolean canLayerAboveSystemBars() {
-        int layer = getWindowLayerFromType();
-        int navLayer = mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_NAVIGATION_BAR,
-                mOwnerCanManageAppTokens);
-        return mOwnerCanManageAppTokens && (layer > navLayer);
-    }
-
     int getWindowLayerFromType() {
         return mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, mOwnerCanManageAppTokens,
                 mRoundedCornerOverlay);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 2a995b2..ec5378f 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -41,6 +41,7 @@
         "com_android_server_companion_virtual_InputController.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
         "com_android_server_display_DisplayControl.cpp",
+        "com_android_server_display_SmallAreaDetectionController.cpp",
         "com_android_server_connectivity_Vpn.cpp",
         "com_android_server_gpu_GpuService.cpp",
         "com_android_server_HardwarePropertiesManagerService.cpp",
diff --git a/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp b/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
new file mode 100644
index 0000000..b256f16
--- /dev/null
+++ b/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SmallAreaDetectionController"
+
+#include <gui/SurfaceComposerClient.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+
+#include "jni.h"
+#include "utils/Log.h"
+
+namespace android {
+static void nativeUpdateSmallAreaDetection(JNIEnv* env, jclass clazz, jintArray juids,
+                                           jfloatArray jthresholds) {
+    if (juids == nullptr || jthresholds == nullptr) return;
+
+    ScopedIntArrayRO uids(env, juids);
+    ScopedFloatArrayRO thresholds(env, jthresholds);
+
+    if (uids.size() != thresholds.size()) {
+        ALOGE("uids size exceeds thresholds size!");
+        return;
+    }
+
+    std::vector<int32_t> uidVector;
+    std::vector<float> thresholdVector;
+    size_t size = uids.size();
+    uidVector.reserve(size);
+    thresholdVector.reserve(size);
+    for (int i = 0; i < size; i++) {
+        uidVector.push_back(static_cast<int32_t>(uids[i]));
+        thresholdVector.push_back(static_cast<float>(thresholds[i]));
+    }
+    SurfaceComposerClient::updateSmallAreaDetection(uidVector, thresholdVector);
+}
+
+static void nativeSetSmallAreaDetectionThreshold(JNIEnv* env, jclass clazz, jint uid,
+                                                 jfloat threshold) {
+    SurfaceComposerClient::setSmallAreaDetectionThreshold(uid, threshold);
+}
+
+static const JNINativeMethod gMethods[] = {
+        {"nativeUpdateSmallAreaDetection", "([I[F)V", (void*)nativeUpdateSmallAreaDetection},
+        {"nativeSetSmallAreaDetectionThreshold", "(IF)V",
+         (void*)nativeSetSmallAreaDetectionThreshold},
+};
+
+int register_android_server_display_smallAreaDetectionController(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/server/display/SmallAreaDetectionController",
+                                    gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 788299c..55deb22 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -372,7 +372,7 @@
     virtual void onPointerDisplayIdChanged(int32_t displayId, const FloatPoint& position);
 
     /* --- PointerControllerPolicyInterface implementation --- */
-    virtual std::shared_ptr<PointerControllerInterface> createPointerController() override;
+    std::shared_ptr<PointerControllerInterface> createPointerController() override;
 
 private:
     sp<InputManagerInterface> mInputManager;
@@ -489,7 +489,7 @@
         dump += StringPrintf(INDENT "Pointer Capture: %s, seq=%" PRIu32 "\n",
                              mLocked.pointerCaptureRequest.enable ? "Enabled" : "Disabled",
                              mLocked.pointerCaptureRequest.seq);
-        forEachPointerControllerLocked([&dump](PointerController& pc) { pc.dump(dump); });
+        forEachPointerControllerLocked([&dump](PointerController& pc) { dump += pc.dump(); });
     } // release lock
     dump += "\n";
 
@@ -530,9 +530,8 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
         mLocked.viewports = viewports;
-        forEachPointerControllerLocked([viewports = std::move(viewports)](PointerController& pc) {
-            pc.onDisplayViewportsUpdated(viewports);
-        });
+        forEachPointerControllerLocked(
+                [&viewports](PointerController& pc) { pc.onDisplayViewportsUpdated(viewports); });
     } // release lock
 
     mInputManager->getReader().requestRefreshConfiguration(
@@ -733,7 +732,13 @@
     if (controller == nullptr) {
         ensureSpriteControllerLocked();
 
-        controller = PointerController::create(this, mLooper, *mLocked.spriteController);
+        static const bool ENABLE_POINTER_CHOREOGRAPHER =
+                sysprop::InputProperties::enable_pointer_choreographer().value_or(false);
+
+        // Disable the functionality of the legacy PointerController if PointerChoreographer is
+        // enabled.
+        controller = PointerController::create(this, mLooper, *mLocked.spriteController,
+                                               /*enabled=*/!ENABLE_POINTER_CHOREOGRAPHER);
         mLocked.legacyPointerController = controller;
         updateInactivityTimeoutLocked();
     }
@@ -745,7 +750,7 @@
     std::scoped_lock _l(mLock);
     ensureSpriteControllerLocked();
     std::shared_ptr<PointerController> pc =
-            PointerController::create(this, mLooper, *mLocked.spriteController);
+            PointerController::create(this, mLooper, *mLocked.spriteController, /*enabled=*/true);
     mLocked.pointerControllers.emplace_back(pc);
     return pc;
 }
diff --git a/services/core/jni/gnss/GnssVisibilityControlCallback.cpp b/services/core/jni/gnss/GnssVisibilityControlCallback.cpp
index ec215f1..bc57c1d 100644
--- a/services/core/jni/gnss/GnssVisibilityControlCallback.cpp
+++ b/services/core/jni/gnss/GnssVisibilityControlCallback.cpp
@@ -73,7 +73,7 @@
 
 template <>
 jstring ToJstring(JNIEnv* env, const String16& value) {
-    const char16_t* str = value.string();
+    const char16_t* str = value.c_str();
     size_t len = value.size();
     return env->NewString(reinterpret_cast<const jchar*>(str), len);
 }
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 97d7be6..f6f6737 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -67,6 +67,7 @@
 int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
 int register_com_android_server_display_DisplayControl(JNIEnv* env);
 int register_com_android_server_SystemClockTime(JNIEnv* env);
+int register_android_server_display_smallAreaDetectionController(JNIEnv* env);
 };
 
 using namespace android;
@@ -126,5 +127,6 @@
     register_com_android_server_wm_TaskFpsCallbackController(env);
     register_com_android_server_display_DisplayControl(env);
     register_com_android_server_SystemClockTime(env);
+    register_android_server_display_smallAreaDetectionController(env);
     return JNI_VERSION_1_4;
 }
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 d833fbd..d22e02e 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -67,6 +67,18 @@
                 <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowIncrease">
                     <xs:annotation name="final"/>
                 </xs:element>
+                <!-- Ramp speed used to decrease the screen brightness when in idle mode.
+                     In framework brightness units per second. Must exist with
+                     screenBrightnessRampSlowIncreaseIdle-->
+                <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowDecreaseIdle">
+                    <xs:annotation name="final"/>
+                </xs:element>
+                <!-- Ramp speed used to decrease the screen brightness when in idle mode.
+                     In framework brightness units per second. Must exist with
+                     screenBrightnessRampSlowDecreaseIdle-->
+                <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowIncreaseIdle">
+                    <xs:annotation name="final"/>
+                </xs:element>
                 <!-- Maximum time in milliseconds that a brightness increase animation
                      can take. -->
                 <xs:element type="xs:nonNegativeInteger" name="screenBrightnessRampIncreaseMaxMillis">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index d2ac1aae..6364c1f 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -115,7 +115,9 @@
     method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease();
     method public final java.math.BigInteger getScreenBrightnessRampIncreaseMaxMillis();
     method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease();
+    method public final java.math.BigDecimal getScreenBrightnessRampSlowDecreaseIdle();
     method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
+    method public final java.math.BigDecimal getScreenBrightnessRampSlowIncreaseIdle();
     method public final com.android.server.display.config.SensorDetails getScreenOffBrightnessSensor();
     method public final com.android.server.display.config.IntegerArray getScreenOffBrightnessSensorValueToLux();
     method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();
@@ -142,7 +144,9 @@
     method public final void setScreenBrightnessRampFastIncrease(java.math.BigDecimal);
     method public final void setScreenBrightnessRampIncreaseMaxMillis(java.math.BigInteger);
     method public final void setScreenBrightnessRampSlowDecrease(java.math.BigDecimal);
+    method public final void setScreenBrightnessRampSlowDecreaseIdle(java.math.BigDecimal);
     method public final void setScreenBrightnessRampSlowIncrease(java.math.BigDecimal);
+    method public final void setScreenBrightnessRampSlowIncreaseIdle(java.math.BigDecimal);
     method public final void setScreenOffBrightnessSensor(com.android.server.display.config.SensorDetails);
     method public final void setScreenOffBrightnessSensorValueToLux(com.android.server.display.config.IntegerArray);
     method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index af1bac8..438a9d6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -680,7 +680,7 @@
     // to decide whether an existing policy in the {@link #DEVICE_POLICIES_XML} needs to
     // be upgraded. See {@link PolicyVersionUpgrader} on instructions how to add an upgrade
     // step.
-    static final int DPMS_VERSION = 5;
+    static final int DPMS_VERSION = 6;
 
     static {
         SECURE_SETTINGS_ALLOWLIST = new ArraySet<>();
@@ -876,8 +876,7 @@
     private static final boolean DEFAULT_ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG = true;
 
     // TODO(b/265683382) remove the flag after rollout.
-    private static final String KEEP_PROFILES_RUNNING_FLAG = "enable_keep_profiles_running";
-    public static final boolean DEFAULT_KEEP_PROFILES_RUNNING_FLAG = true;
+    public static final boolean DEFAULT_KEEP_PROFILES_RUNNING_FLAG = false;
 
     // TODO(b/261999445) remove the flag after rollout.
     private static final String HEADLESS_FLAG = "headless";
@@ -2594,6 +2593,12 @@
                 mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, true,
                         userHandle);
             }
+            // Enforcing the restriction of private profile creation in case device owner is set.
+            if (!mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_PRIVATE_PROFILE, userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, true,
+                        userHandle);
+            }
             // Creation of managed profile is restricted in case device owner is set, enforcing this
             // restriction by setting user level restriction at time of device owner setup.
             if (!mUserManager.hasUserRestriction(
@@ -4036,6 +4041,15 @@
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                             false, user);
                 }
+
+                // When a device owner is set, the system automatically restricts adding a
+                // private profile.
+                // Remove this restriction when the device owner is cleared.
+                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                        user)) {
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                            false, user);
+                }
             }
         } else {
             // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state
@@ -4061,6 +4075,15 @@
                         false,
                         userHandle);
             }
+
+            // When a device owner is set, the system automatically restricts adding a
+            // private profile.
+            // Remove this restriction when the device owner is cleared.
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                    userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                        false, userHandle);
+            }
         }
     }
 
@@ -9423,6 +9446,11 @@
                         mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                                 true,
                                 UserHandle.of(u));
+
+                        // Restrict adding a private profile when a device owner is set.
+                        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                                true,
+                                UserHandle.of(u));
                     }
                 } else {
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
@@ -9435,6 +9463,9 @@
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                             true,
                             UserHandle.of(userId));
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                            true,
+                            UserHandle.of(userId));
                 }
                 // TODO Send to system too?
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
@@ -13200,6 +13231,8 @@
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ADD_CLONE_PROFILE, new String[]{MANAGE_DEVICE_POLICY_PROFILES});
         USER_RESTRICTION_PERMISSIONS.put(
+                UserManager.DISALLOW_ADD_PRIVATE_PROFILE, new String[]{MANAGE_DEVICE_POLICY_PROFILES});
+        USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ADD_USER, new String[]{MANAGE_DEVICE_POLICY_MODIFY_USERS});
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ADD_WIFI_CONFIG, new String[]{MANAGE_DEVICE_POLICY_WIFI});
@@ -22977,10 +23010,7 @@
     }
 
     private static boolean isKeepProfilesRunningFlagEnabled() {
-        return DeviceConfig.getBoolean(
-                NAMESPACE_DEVICE_POLICY_MANAGER,
-                KEEP_PROFILES_RUNNING_FLAG,
-                DEFAULT_KEEP_PROFILES_RUNNING_FLAG);
+        return DEFAULT_KEEP_PROFILES_RUNNING_FLAG;
     }
 
     private boolean isUnicornFlagEnabled() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 7a877b9..0fc8c5e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -426,6 +426,7 @@
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, /* flags= */ 0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 733b1d9..f060426 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -117,6 +117,19 @@
             currentVersion = 5;
         }
 
+        if (currentVersion == 5) {
+            Slog.i(LOG_TAG, String.format("Upgrading from version %d", currentVersion));
+            // No-op upgrade here:
+            // DevicePolicyData.mEffectiveKeepProfilesRunning is only stored in XML file when it is
+            // different from its default value, otherwise the tag is not written. When loading, if
+            // the tag is missing, the field retains the value previously assigned in the
+            // constructor, which is the default value.
+            // In version 5 the default value was 'true', in version 6 it is 'false', so when
+            // loading XML version 5 we need to initialize the field to 'true' for it to be restored
+            // correctly in case the tag is missing. This is done in loadDataForUser().
+            currentVersion = 6;
+        }
+
         writePoliciesAndVersion(allUsers, allUsersData, ownersData, currentVersion);
     }
 
@@ -282,6 +295,10 @@
     private DevicePolicyData loadDataForUser(
             int userId, int loadVersion, ComponentName ownerComponent) {
         DevicePolicyData policy = new DevicePolicyData(userId);
+        // See version 5 -> 6 step in upgradePolicy()
+        if (loadVersion == 5 && userId == UserHandle.USER_SYSTEM) {
+            policy.mEffectiveKeepProfilesRunning = true;
+        }
         DevicePolicyData.load(policy,
                 mProvider.makeDevicePoliciesJournaledFile(userId),
                 mProvider.getAdminInfoSupplier(userId),
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 9a8e421..8684dbe 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -111,7 +111,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+            cancelNotification();
             if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
                 onBugreportSharingAccepted();
             } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
@@ -213,8 +213,7 @@
             mRemoteBugreportServiceIsActive.set(true);
             mRemoteBugreportSharingAccepted.set(false);
             registerRemoteBugreportReceivers();
-            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                    buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+            notify(NOTIFICATION_BUGREPORT_STARTED);
             mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
             return true;
         } catch (RemoteException re) {
@@ -258,13 +257,10 @@
         final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
         if (mRemoteBugreportSharingAccepted.get()) {
             shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
-            mInjector.getNotificationManager().cancel(LOG_TAG,
-                    NOTIFICATION_ID);
+            cancelNotification();
         } else {
             mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
-            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                    buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
-                    UserHandle.ALL);
+            notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
         }
         mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
     }
@@ -274,7 +270,7 @@
         mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
         mRemoteBugreportSharingAccepted.set(false);
         mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
-        mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+        cancelNotification();
         final Bundle extras = new Bundle();
         extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
                 DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
@@ -289,9 +285,7 @@
         if (uriAndHash != null) {
             shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
         } else if (mRemoteBugreportServiceIsActive.get()) {
-            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                    buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
-                    UserHandle.ALL);
+            notify(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED);
         }
     }
 
@@ -340,7 +334,16 @@
         filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
         filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
         mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
-        mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
-                buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+        notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
+    }
+
+    private void notify(@RemoteBugreportNotificationType int type) {
+        mInjector.getNotificationManager()
+                .notifyAsUser(LOG_TAG, NOTIFICATION_ID, buildNotification(type), UserHandle.ALL);
+    }
+
+    private void cancelNotification() {
+        mInjector.getNotificationManager()
+                .cancelAsUser(LOG_TAG, NOTIFICATION_ID, UserHandle.ALL);
     }
 }
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index ea5ce65..49962ea 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -52,7 +52,6 @@
     public static final int IPV6_ADDR_BITS = 128;
     public static final int IPV6_ADDR_LEN = 16;
     public static final int IPV6_MIN_MTU = 1280;
-    public static final int RFC7421_PREFIX_LENGTH = 64;
 
     /**
      * ICMP common (v4/v6) constants.
diff --git a/services/permission/TEST_MAPPING b/services/permission/TEST_MAPPING
index b2dcf37..24323c8 100644
--- a/services/permission/TEST_MAPPING
+++ b/services/permission/TEST_MAPPING
@@ -4,7 +4,7 @@
             "name": "CtsPermissionTestCases",
             "options": [
                 {
-                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
                 },
                 {
                     "include-filter": "android.permission.cts.BackgroundPermissionsTest"
@@ -32,7 +32,7 @@
             "name": "CtsPermissionPolicyTestCases",
             "options": [
                 {
-                    "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
                 },
                 {
                     "include-filter": "android.permissionpolicy.cts.RestrictedPermissionsTest"
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index e8acb06..6ff7b26 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -16,15 +16,20 @@
 
 package com.android.inputmethodservice;
 
+import static android.view.WindowInsets.Type.captionBar;
+
 import static com.android.compatibility.common.util.SystemUtil.eventually;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Insets;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.support.test.uiautomator.By;
@@ -32,6 +37,7 @@
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
 import android.util.Log;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
@@ -592,6 +598,20 @@
                 false /* orientationPortrait */);
     }
 
+    /**
+     * This checks that when the system navigation bar is not created (e.g. emulator),
+     * then the IME caption bar is also not created.
+     */
+    @Test
+    public void testNoNavigationBar_thenImeNoCaptionBar() throws Exception {
+        boolean hasNavigationBar = WindowManagerGlobal.getWindowManagerService()
+                .hasNavigationBar(mInputMethodService.getDisplayId());
+        assumeFalse("Must not have a navigation bar", hasNavigationBar);
+
+        assertEquals(Insets.NONE, mInputMethodService.getWindow().getWindow().getDecorView()
+                .getRootWindowInsets().getInsetsIgnoringVisibility(captionBar()));
+    }
+
     private void verifyInputViewStatus(
             Runnable runnable, boolean expected, boolean inputViewStarted)
             throws InterruptedException {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java
index a805e5c..bea6543 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -125,7 +125,7 @@
         Assert.assertNull(pri.mBroadcastUsers);
 
         // populateUsers with nothing leaves nothing
-        pri.populateUsers(null, setting);
+        pri.populateBroadcastUsers(setting);
         Assert.assertNull(pri.mBroadcastUsers);
 
         // Create a real (non-null) PackageSetting and confirm that the removed
@@ -139,9 +139,10 @@
                 .setSecondaryCpuAbiString("secondaryCpuAbiString")
                 .setCpuAbiOverrideString("cpuAbiOverrideString")
                 .build();
-        pri.populateUsers(new int[]{
+        pri.mRemovedUsers = new int[]{
                 1, 2, 3, 4, 5
-        }, setting);
+        };
+        pri.populateBroadcastUsers(setting);
         Assert.assertNotNull(pri.mBroadcastUsers);
         Assert.assertEquals(5, pri.mBroadcastUsers.length);
         Assert.assertNotNull(pri.mInstantUserIds);
@@ -151,9 +152,10 @@
         pri.mBroadcastUsers = null;
         final int EXCLUDED_USER_ID = 4;
         setting.setInstantApp(true, EXCLUDED_USER_ID);
-        pri.populateUsers(new int[]{
+        pri.mRemovedUsers = new int[]{
                 1, 2, 3, EXCLUDED_USER_ID, 5
-        }, setting);
+        };
+        pri.populateBroadcastUsers(setting);
         Assert.assertNotNull(pri.mBroadcastUsers);
         Assert.assertEquals(4, pri.mBroadcastUsers.length);
         Assert.assertNotNull(pri.mInstantUserIds);
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/PackageManagerLocalSnapshotTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/PackageManagerLocalSnapshotTest.kt
index 5f26d6f..cd37674 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/PackageManagerLocalSnapshotTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/PackageManagerLocalSnapshotTest.kt
@@ -31,6 +31,7 @@
 import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito.doReturn
 import kotlin.test.assertFailsWith
 
 class PackageManagerLocalSnapshotTest {
@@ -154,7 +155,7 @@
             put(packageStateUser0.packageName, packageStateUser0)
             put(packageStateUser10.packageName, packageStateUser10)
         }
-        whenever(this.packageStates) { packageStates }
+        doReturn(packageStates).whenever(this).packageStates
         whenever(getPackageStateFiltered(anyString(), anyInt(), anyInt())) {
             packageStates[arguments[0]]?.takeUnless {
                 shouldFilterApplication(it, arguments[1] as Int, arguments[2] as Int)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 55645d7..9fbf86e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -48,6 +48,7 @@
 import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.anyLong
 import org.mockito.Mockito.anyString
+import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verifyNoMoreInteractions
@@ -351,12 +352,12 @@
                 whenever(this.domainSetId) { domainSetId }
                 whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT }
                 whenever(getUserStateOrDefault(1)) { PackageUserStateInternal.DEFAULT }
-                whenever(userStates) {
+                doReturn(
                     SparseArray<PackageUserStateInternal>().apply {
                         this[0] = PackageUserStateInternal.DEFAULT
                         this[1] = PackageUserStateInternal.DEFAULT
                     }
-                }
+                ).whenever(this).userStates
                 whenever(isSystem) { false }
                 whenever(signingDetails) { SigningDetails.UNKNOWN }
             }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index 86c4335..47d9196 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -44,6 +44,7 @@
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito.doReturn
 import java.util.UUID
 import java.util.concurrent.atomic.AtomicBoolean
 import kotlin.test.assertFailsWith
@@ -555,12 +556,12 @@
         whenever(this.domainSetId) { domainSetId }
         whenever(getUserStateOrDefault(0)) { pkgUserState0() }
         whenever(getUserStateOrDefault(1)) { pkgUserState1() }
-        whenever(userStates) {
+        doReturn(
             SparseArray<PackageUserStateInternal>().apply {
                 this[0] = pkgUserState0()
                 this[1] = pkgUserState1()
             }
-        }
+        ).whenever(this).userStates
         whenever(isSystem) { false }
     }
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index e55ff3b..98d7801 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -1084,12 +1084,12 @@
         whenever(this.domainSetId) { domainSetId }
         whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT }
         whenever(getUserStateOrDefault(10)) { PackageUserStateInternal.DEFAULT }
-        whenever(userStates) {
+        doReturn(
             SparseArray<PackageUserStateInternal>().apply {
                 this[0] = PackageUserStateInternal.DEFAULT
                 this[1] = PackageUserStateInternal.DEFAULT
             }
-        }
+        ).whenever(this).userStates
         whenever(isSystem) { isSystemApp }
 
         val mockSigningDetails = SigningDetails(arrayOf(spy(Signature(signature)) {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 427b5b3..4a211df 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -41,6 +41,7 @@
 import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.anyLong
 import org.mockito.Mockito.anyString
+import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.verify
 import java.util.UUID
@@ -218,12 +219,12 @@
             whenever(domainSetId) { TEST_UUID }
             whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT }
             whenever(getUserStateOrDefault(10)) { PackageUserStateInternal.DEFAULT }
-            whenever(userStates) {
+            doReturn(
                 SparseArray<PackageUserStateInternal>().apply {
                     this[0] = PackageUserStateInternal.DEFAULT
                     this[1] = PackageUserStateInternal.DEFAULT
                 }
-            }
+            ).whenever(this).userStates
             whenever(isSystem) { false }
         }
     }
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 6bb5f39..d54d608 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -41,6 +41,8 @@
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito.doReturn
+
 import java.util.UUID
 
 class DomainVerificationUserStateOverrideTest {
@@ -155,12 +157,12 @@
             whenever(this.domainSetId) { domainSetId }
             whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT }
             whenever(getUserStateOrDefault(1)) { PackageUserStateInternal.DEFAULT }
-            whenever(userStates) {
+            doReturn(
                 SparseArray<PackageUserStateInternal>().apply {
                     this[0] = PackageUserStateInternal.DEFAULT
                     this[1] = PackageUserStateInternal.DEFAULT
                 }
-            }
+            ).whenever(this).userStates
             whenever(isSystem) { false }
         }
 
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index fb14419..e28028f9 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -35,6 +35,7 @@
         "mockingservicestests-utils-mockito",
         "platform-compat-test-rules",
         "platform-test-annotations",
+        "service-permission.stubs.system_server",
         "services.core",
         "servicestests-utils",
         "testables",
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index d16c37a4..2bdebe2 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -267,7 +267,8 @@
                 /* shouldResetShortTermModel= */ true);
 
         // There should be a user data point added to the mapper.
-        verify(mBrightnessMappingStrategy).addUserDataPoint(1000f, 0.5f);
+        verify(mBrightnessMappingStrategy).addUserDataPoint(/* lux= */ 1000f,
+                /* brightness= */ 0.5f);
     }
 
     @Test
@@ -295,7 +296,8 @@
         mController.recalculateSplines(true, adjustments);
         verify(mBrightnessMappingStrategy).clearUserDataPoints();
         verify(mBrightnessMappingStrategy).recalculateSplines(true, adjustments);
-        verify(mBrightnessMappingStrategy, times(2)).addUserDataPoint(currentLux, 0.5f);
+        verify(mBrightnessMappingStrategy, times(2)).addUserDataPoint(currentLux,
+                /* brightness= */ 0.5f);
 
         clearInvocations(mBrightnessMappingStrategy);
 
@@ -342,7 +344,7 @@
         // Verify only happens on the first configure. (i.e. not again when switching back)
         // Intentionally using any() to ensure it's not called whatsoever.
         verify(mBrightnessMappingStrategy, times(1))
-                .addUserDataPoint(123.0f, 0.5f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(1))
                 .addUserDataPoint(anyFloat(), anyFloat());
     }
@@ -385,7 +387,7 @@
         // Verify that we add the data point once when the user sets it, and again when we return
         // interactive mode.
         verify(mBrightnessMappingStrategy, times(2))
-                .addUserDataPoint(123.0f, 0.51f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.51f);
     }
 
     @Test
@@ -428,7 +430,7 @@
         // Verify only happens on the first configure. (i.e. not again when switching back)
         // Intentionally using any() to ensure it's not called whatsoever.
         verify(mBrightnessMappingStrategy, times(1))
-                .addUserDataPoint(123.0f, 0.5f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(1))
                 .addUserDataPoint(anyFloat(), anyFloat());
     }
@@ -474,7 +476,7 @@
         // Verify this happens on the first configure and again when switching back
         // Intentionally using any() to ensure it's not called any other times whatsoever.
         verify(mBrightnessMappingStrategy, times(2))
-                .addUserDataPoint(123.0f, 0.5f);
+                .addUserDataPoint(/* lux= */ 123.0f, /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(2))
                 .addUserDataPoint(anyFloat(), anyFloat());
     }
@@ -533,7 +535,8 @@
                 /* shouldResetShortTermModel= */ true);
 
         // There should be a user data point added to the mapper.
-        verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f);
+        verify(mBrightnessMappingStrategy, times(1)).addUserDataPoint(/* lux= */ 1000f,
+                /* brightness= */ 0.5f);
         verify(mBrightnessMappingStrategy, times(2)).setBrightnessConfiguration(any());
         verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt());
 
@@ -559,7 +562,8 @@
                 /* shouldResetShortTermModel= */ true);
 
         // Ensure we use the correct mapping strategy
-        verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f);
+        verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(/* lux= */ 1000f,
+                /* brightness= */ 0.5f);
     }
 
     @Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index ee7826f..97e5826 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -445,7 +445,7 @@
 
         // Add a data point in the middle of the curve where the user has set the brightness max
         final int idx = LUX_LEVELS.length / 2;
-        strategy.addUserDataPoint(LUX_LEVELS[idx], 1.0f);
+        strategy.addUserDataPoint(LUX_LEVELS[idx], /* brightness= */ 1.0f);
 
         // Then make sure that all control points after the middle lux level are also set to max...
         for (int i = idx; i < LUX_LEVELS.length; i++) {
@@ -662,11 +662,11 @@
                 GAMMA_CORRECTION_NITS);
         BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
                 mMockDwbc);
-        assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
-        strategy.addUserDataPoint(2500, 1.0f);
-        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
-        strategy.addUserDataPoint(2500, 0.0f);
-        assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
+        assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
+        strategy.addUserDataPoint(/* lux= */ 2500, /* brightness= */ 1.0f);
+        assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
+        strategy.addUserDataPoint(/* lux= */ 2500, /* brightness= */ 0.0f);
+        assertEquals(-1.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
     }
 
     @Test
@@ -701,7 +701,7 @@
         // Similarly, if we set a user data point at (x4, 1.0), the adjustment should be 1 - y4.
         adjustment = 1.0f - y4;
         gamma = (float) MathUtils.pow(MAXIMUM_GAMMA, -adjustment);
-        strategy.addUserDataPoint(x4, 1.0f);
+        strategy.addUserDataPoint(x4, /* brightness= */ 1.0f);
         assertEquals(MathUtils.pow(y0, gamma), strategy.getBrightness(x0), 0.0001f /* tolerance */);
         assertEquals(MathUtils.pow(y2, gamma), strategy.getBrightness(x2), 0.0001f /* tolerance */);
         assertEquals(1.0f, strategy.getBrightness(x4), 0.0001f /* tolerance */);
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 d099693..a23539e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -28,6 +28,7 @@
 import static com.android.server.display.VirtualDisplayAdapter.UNIQUE_ID_PREFIX;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -53,6 +54,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.PropertyInvalidatedCache;
 import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.IVirtualDeviceManager;
@@ -61,6 +64,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -110,6 +114,7 @@
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.lights.LightsManager;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.sensors.SensorManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -288,10 +293,11 @@
     @Mock LocalDisplayAdapter.SurfaceControlProxy mSurfaceControlProxy;
     @Mock IBinder mMockDisplayToken;
     @Mock SensorManagerInternal mMockSensorManagerInternal;
-
     @Mock SensorManager mSensorManager;
-
     @Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
+    @Mock PackageManagerInternal mMockPackageManagerInternal;
+    @Mock UserManagerInternal mMockUserManagerInternal;
+
 
     @Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
     @Mock DisplayManagerFlags mMockFlags;
@@ -312,6 +318,10 @@
         LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
         LocalServices.addService(
                 VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
         // TODO: b/287945043
         mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         mResources = Mockito.spy(mContext.getResources());
@@ -627,7 +637,7 @@
      * Tests that the virtual display is created along-side the default display.
      */
     @Test
-    public void testStartVirtualDisplayWithDefaultDisplay_Succeeds() throws Exception {
+    public void testStartVirtualDisplayWithDefaultDisplay_Succeeds() {
         DisplayManagerService displayManager =
                 new DisplayManagerService(mContext, mShortMockedInjector);
         registerDefaultDisplays(displayManager);
@@ -663,7 +673,7 @@
      * internal state for things like display cutout when nonOverrideDisplayInfo is changed.
      */
     @Test
-    public void testShouldNotifyChangeWhenNonOverrideDisplayInfoChanged() throws Exception {
+    public void testShouldNotifyChangeWhenNonOverrideDisplayInfoChanged() {
         DisplayManagerService displayManager =
                 new DisplayManagerService(mContext, mShortMockedInjector);
         registerDefaultDisplays(displayManager);
@@ -1486,7 +1496,7 @@
      * a virtual device, even if ADD_TRUSTED_DISPLAY is not granted.
      */
     @Test
-    public void testOwnDisplayGroup_allowCreationWithVirtualDevice()  throws Exception {
+    public void testOwnDisplayGroup_allowCreationWithVirtualDevice() throws Exception {
         DisplayManagerService displayManager =
                 new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerInternal localService = displayManager.new LocalService();
@@ -1650,7 +1660,7 @@
      */
     @Test
     @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
-    public  void testDisplayInfoFrameRateOverrideModeCompat() throws Exception {
+    public  void testDisplayInfoFrameRateOverrideModeCompat() {
         testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ false);
     }
 
@@ -1659,7 +1669,7 @@
      */
     @Test
     @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
-    public  void testDisplayInfoFrameRateOverrideMode() throws Exception {
+    public  void testDisplayInfoFrameRateOverrideMode() {
         testDisplayInfoFrameRateOverrideModeCompat(/*compatChangeEnabled*/ true);
     }
 
@@ -1742,7 +1752,7 @@
      */
     @Test
     @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
-    public  void testDisplayInfoRenderFrameRateModeCompat() throws Exception {
+    public  void testDisplayInfoRenderFrameRateModeCompat() {
         testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ false);
     }
 
@@ -1751,7 +1761,7 @@
      */
     @Test
     @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
-    public  void testDisplayInfoRenderFrameRateMode() throws Exception {
+    public  void testDisplayInfoRenderFrameRateMode() {
         testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ true);
     }
 
@@ -2104,10 +2114,11 @@
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
         bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
 
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
@@ -2124,16 +2135,19 @@
         DisplayManagerInternal localService = displayManager.new LocalService();
         DisplayManagerService.BinderService bs = displayManager.new BinderService();
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
-        // Create default display device
-        createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
-
         bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
         localService.registerDisplayGroupListener(callback);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
+        // Create default display device
+        createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+        callback.waitForExpectedEvent();
+        callback.clear();
 
+        callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
@@ -2151,8 +2165,9 @@
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
         bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
 
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_CONNECTED,
                 EVENT_DISPLAY_ADDED).inOrder();
@@ -2166,18 +2181,22 @@
         DisplayManagerService.BinderService bs = displayManager.new BinderService();
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         // Create default display device
         createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
-        bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
+        callback.waitForExpectedEvent();
+        callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
 
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
         displayManager.enableConnectedDisplay(display.getDisplayIdLocked(), /* enabled= */ true);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(display.isEnabledLocked()).isTrue();
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED).inOrder();
@@ -2190,11 +2209,15 @@
         DisplayManagerService.BinderService bs = displayManager.new BinderService();
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         // Create default display device
         createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+        callback.waitForExpectedEvent();
         bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
+        // Withouts permission, we cannot get the CONNECTED event.
         waitForIdleHandler(displayManager.getDisplayHandler());
         callback.clear();
         LogicalDisplay display =
@@ -2212,19 +2235,22 @@
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
         bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+        callback.expectsEvent(EVENT_DISPLAY_REMOVED);
         logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ false);
         logicalDisplayMapper.updateLogicalDisplays();
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
 
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);
         logicalDisplayMapper.updateLogicalDisplays();
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED);
     }
@@ -2237,16 +2263,18 @@
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
         bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
 
+        callback.expectsEvent(EVENT_DISPLAY_REMOVED);
         logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ false);
         logicalDisplayMapper.updateLogicalDisplays();
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED);
     }
@@ -2259,23 +2287,26 @@
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         DisplayManagerInternal localService = displayManager.new LocalService();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
-        // Create default display device
-        createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
         bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
         localService.registerDisplayGroupListener(callback);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
+        // Create default display device
+        createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+        callback.waitForExpectedEvent();
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);
         logicalDisplayMapper.updateLogicalDisplays();
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
 
+        callback.expectsEvent(EVENT_DISPLAY_REMOVED);
         logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ false);
         logicalDisplayMapper.updateLogicalDisplays();
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(display.isEnabledLocked()).isFalse();
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED);
@@ -2288,18 +2319,20 @@
         DisplayManagerService.BinderService bs = displayManager.new BinderService();
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+        bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         // Create default display device
         createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
-        bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS);
+        callback.waitForExpectedEvent();
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
         int displayId = display.getDisplayIdLocked();
         logicalDisplayMapper.setEnabledLocked(display, /* isEnabled= */ true);
         logicalDisplayMapper.updateLogicalDisplays();
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
 
         assertThrows(SecurityException.class, () -> bs.disableConnectedDisplay(displayId));
@@ -2314,23 +2347,27 @@
         DisplayManagerInternal localService = displayManager.new LocalService();
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
-        // Create default display device
-        createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
         bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
         localService.registerDisplayGroupListener(callback);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
+        // Create default display device'
+        createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+        callback.waitForExpectedEvent();
+        callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
         LogicalDisplay display = logicalDisplayMapper.getDisplayLocked(displayDevice);
         int groupId = display.getDisplayInfoLocked().displayGroupId;
         DisplayGroup group = logicalDisplayMapper.getDisplayGroupLocked(groupId);
         assertThat(group.getSizeLocked()).isEqualTo(1);
 
+        callback.expectsEvent(DISPLAY_GROUP_EVENT_REMOVED);
         display.setPrimaryDisplayDeviceLocked(null);
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(group.getSizeLocked()).isEqualTo(0);
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_DISCONNECTED,
@@ -2357,20 +2394,23 @@
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
         bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_CONNECTED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
         int displayId = display.getDisplayIdLocked();
         displayManager.enableConnectedDisplay(displayId, /* enabled= */ true);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
 
+        callback.expectsEvent(EVENT_DISPLAY_DISCONNECTED);
         display.setPrimaryDisplayDeviceLocked(null);
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(logicalDisplayMapper.getDisplayLocked(displayId, true)).isNull();
         assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_REMOVED,
@@ -2386,17 +2426,19 @@
         LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
         FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
         bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+        callback.expectsEvent(EVENT_DISPLAY_ADDED);
         FakeDisplayDevice displayDevice =
                 createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
         LogicalDisplay display =
                 logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
         callback.clear();
 
+        callback.expectsEvent(EVENT_DISPLAY_DISCONNECTED);
         display.setPrimaryDisplayDeviceLocked(null);
         displayManager.getDisplayDeviceRepository()
                 .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
-        waitForIdleHandler(displayManager.getDisplayHandler());
+        callback.waitForExpectedEvent();
 
         assertThat(logicalDisplayMapper.getDisplayLocked(displayDevice,
                 /* includeDisabled= */ true)).isNull();
@@ -2675,6 +2717,12 @@
         int mDisplayId;
         List<String> mReceivedEvents = new ArrayList<>();
 
+        @Nullable
+        private String mExpectedEvent;
+
+        @NonNull
+        private volatile CountDownLatch mLatch = new CountDownLatch(0);
+
         FakeDisplayManagerCallback(int displayId) {
             mDisplayId = displayId;
         }
@@ -2683,6 +2731,30 @@
             mDisplayId = -1;
         }
 
+        void expectsEvent(@NonNull String event) {
+            mExpectedEvent = event;
+            mLatch = new CountDownLatch(1);
+        }
+
+        void waitForExpectedEvent() {
+            waitForExpectedEvent(Duration.ofSeconds(1));
+        }
+
+        void waitForExpectedEvent(Duration timeout) {
+            try {
+                assertWithMessage("Event '" + mExpectedEvent + "' is received.")
+                        .that(mLatch.await(timeout.toMillis(), TimeUnit.MILLISECONDS)).isTrue();
+            } catch (InterruptedException ex) {
+                throw new AssertionError("Waiting for expected event interrupted", ex);
+            }
+        }
+
+        private void eventSeen(String event) {
+            if (event.equals(mExpectedEvent)) {
+                mLatch.countDown();
+            }
+        }
+
         @Override
         public void onDisplayEvent(int displayId, int event) {
             if (mDisplayId != -1 && displayId != mDisplayId) {
@@ -2693,22 +2765,27 @@
             // 1 - The error produced is a lot easier to read
             // 2 - The values used for display and group events are the same, strings are used to
             // differentiate them easily.
-            mReceivedEvents.add(eventTypeToString(event));
+            String eventName = eventTypeToString(event);
+            mReceivedEvents.add(eventName);
+            eventSeen(eventName);
         }
 
         @Override
         public void onDisplayGroupAdded(int groupId) {
             mReceivedEvents.add(DISPLAY_GROUP_EVENT_ADDED);
+            eventSeen(DISPLAY_GROUP_EVENT_ADDED);
         }
 
         @Override
         public void onDisplayGroupRemoved(int groupId) {
             mReceivedEvents.add(DISPLAY_GROUP_EVENT_REMOVED);
+            eventSeen(DISPLAY_GROUP_EVENT_REMOVED);
         }
 
         @Override
         public void onDisplayGroupChanged(int groupId) {
             mReceivedEvents.add(DISPLAY_GROUP_EVENT_CHANGED);
+            eventSeen(DISPLAY_GROUP_EVENT_CHANGED);
         }
 
         public void clear() {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
index 4cbdd09..e7dc48e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -101,6 +101,8 @@
     private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE = 0.5f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE = 0.6f;
 
     private OffsettableClock mClock;
     private TestLooper mTestLooper;
@@ -1116,6 +1118,63 @@
         verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true);
     }
 
+    @Test
+    public void testRampRatesIdle() {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        float brightness = 0.6f;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+        when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+        brightness = 0.05f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+
+        // The second time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE));
+
+        brightness = 0.9f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+        // The third time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE));
+    }
+
+    @Test
+    public void testPowerStateStopsOnDpcStop() {
+        // Set up
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1);
+
+        // Stop dpc
+        mHolder.dpc.stop();
+        advanceTime(1);
+
+        // Ensure dps has stopped
+        verify(mHolder.displayPowerState, times(1)).stop();
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -1187,6 +1246,10 @@
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE);
         when(displayDeviceConfigMock.getBrightnessRampSlowIncrease())
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE);
     }
 
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
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 68bbcbc..2640390 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -101,6 +101,8 @@
     private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE = 0.5f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE = 0.6f;
 
     private OffsettableClock mClock;
     private TestLooper mTestLooper;
@@ -1123,6 +1125,63 @@
         verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true);
     }
 
+    @Test
+    public void testRampRatesIdle() {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        float brightness = 0.6f;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+        when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+        brightness = 0.05f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+
+        // The second time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE));
+
+        brightness = 0.9f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+        // The third time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE));
+    }
+
+    @Test
+    public void testPowerStateStopsOnDpcStop() {
+        // Set up
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1);
+
+        // Stop dpc
+        mHolder.dpc.stop();
+        advanceTime(1);
+
+        // Ensure dps has stopped
+        verify(mHolder.displayPowerState, times(1)).stop();
+    }
+
     private void advanceTime(long timeMs) {
         mClock.fastForward(timeMs);
         mTestLooper.dispatchAll();
@@ -1186,6 +1245,10 @@
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE);
         when(displayDeviceConfigMock.getBrightnessRampSlowIncrease())
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE);
     }
 
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java
new file mode 100644
index 0000000..167a412
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerStateTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.Mockito.times;
+
+import android.os.Handler;
+import android.os.test.TestLooper;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+
+@SmallTest
+public class DisplayPowerStateTest {
+    private static final int DISPLAY_ID = 123;
+
+    private DisplayPowerState mDisplayPowerState;
+    private TestLooper mTestLooper;
+    @Mock
+    private DisplayBlanker mDisplayBlankerMock;
+    @Mock
+    private ColorFade mColorFadeMock;
+
+    @Rule
+    public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+    @Before
+    public void setUp() {
+        mTestLooper = new TestLooper();
+        mDisplayPowerState = new DisplayPowerState(
+                mDisplayBlankerMock, mColorFadeMock, DISPLAY_ID, Display.STATE_ON,
+                new Handler(mTestLooper.getLooper()));
+    }
+
+    @Test
+    public void testColorFadeStopsOnDpsStop() {
+        mDisplayPowerState.stop();
+        verify(mColorFadeMock, times(1)).stop();
+    }
+}
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 6954435..065dd1f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -44,9 +44,13 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -58,6 +62,7 @@
 import android.os.IThermalService;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.view.Display;
 import android.view.DisplayAddress;
@@ -69,7 +74,7 @@
 import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.display.layout.DisplayIdProducer;
 import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -93,6 +98,7 @@
     private static int sUniqueTestDisplayId = 0;
     private static final int DEVICE_STATE_CLOSED = 0;
     private static final int DEVICE_STATE_OPEN = 2;
+    private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0;
     private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
     private static final File NON_EXISTING_FILE = new File("/non_existing_folder/should_not_exist");
 
@@ -107,7 +113,7 @@
 
     @Mock LogicalDisplayMapper.Listener mListenerMock;
     @Mock Context mContextMock;
-    @Mock FoldSettingWrapper mFoldSettingWrapperMock;
+    @Mock FoldSettingProvider mFoldSettingProviderMock;
     @Mock Resources mResourcesMock;
     @Mock IPowerManager mIPowerManagerMock;
     @Mock IThermalService mIThermalServiceMock;
@@ -120,7 +126,7 @@
     @Captor ArgumentCaptor<Integer> mDisplayEventCaptor;
 
     @Before
-    public void setUp() {
+    public void setUp() throws RemoteException {
         // Share classloader to allow package private access.
         System.setProperty("dexmaker.share_classloader", "true");
         MockitoAnnotations.initMocks(this);
@@ -150,7 +156,9 @@
 
         when(mContextMock.getSystemServiceName(PowerManager.class))
                 .thenReturn(Context.POWER_SERVICE);
-        when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(false);
+        when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(false);
+        when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+        when(mIPowerManagerMock.isInteractive()).thenReturn(true);
         when(mContextMock.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
         when(mContextMock.getResources()).thenReturn(mResourcesMock);
         when(mResourcesMock.getBoolean(
@@ -166,9 +174,10 @@
         when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(false);
         mLooper = new TestLooper();
         mHandler = new Handler(mLooper.getLooper());
-        mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
+        mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mFoldSettingProviderMock,
+                mDisplayDeviceRepo,
                 mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
-                mDeviceStateToLayoutMapSpy, mFoldSettingWrapperMock, mFlagsMock);
+                mDeviceStateToLayoutMapSpy, mFlagsMock);
     }
 
 
@@ -645,8 +654,8 @@
     }
 
     @Test
-    public void testDeviceShouldNotSleepWhenFoldSettingTrue() {
-        when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(true);
+    public void testDeviceShouldNotSleepWhenStayAwakeSettingTrue() {
+        when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(true);
 
         assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
                 DEVICE_STATE_OPEN,
@@ -679,6 +688,26 @@
     }
 
     @Test
+    public void testDeviceShouldPutToSleepWhenSleepSettingTrue() throws RemoteException {
+        when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(true);
+
+        finishBootAndFoldDevice();
+
+        verify(mIPowerManagerMock, atLeastOnce()).goToSleep(anyLong(), anyInt(),
+                eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+    }
+
+    @Test
+    public void testDeviceShouldNotBePutToSleepWhenSleepSettingFalse() throws RemoteException {
+        when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+
+        finishBootAndFoldDevice();
+
+        verify(mIPowerManagerMock, never()).goToSleep(anyLong(), anyInt(),
+                eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+    }
+
+    @Test
     public void testDeviceStateLocked() {
         DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800,
                 FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
@@ -930,6 +959,15 @@
     // Helper Methods
     /////////////////
 
+    private void finishBootAndFoldDevice() {
+        mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN, false);
+        advanceTime(1000);
+        mLogicalDisplayMapper.onBootCompleted();
+        advanceTime(1000);
+        mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED, false);
+        advanceTime(1000);
+    }
+
     private void createDefaultDisplay(Layout layout, DisplayDevice device) {
         createDefaultDisplay(layout, info(device).address);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
new file mode 100644
index 0000000..1ce79a5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static android.os.Process.INVALID_UID;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContextWrapper;
+import android.content.pm.PackageManagerInternal;
+import android.provider.DeviceConfigInterface;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
+
+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;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SmallAreaDetectionControllerTest {
+
+    @Rule
+    public MockitoRule mRule = MockitoJUnit.rule();
+
+    @Mock
+    private PackageManagerInternal mMockPackageManagerInternal;
+    @Mock
+    private UserManagerInternal mMockUserManagerInternal;
+
+    private SmallAreaDetectionController mSmallAreaDetectionController;
+
+    private static final String PKG_A = "com.a.b.c";
+    private static final String PKG_B = "com.d.e.f";
+    private static final String PKG_NOT_INSTALLED = "com.not.installed";
+    private static final float THRESHOLD_A = 0.05f;
+    private static final float THRESHOLD_B = 0.07f;
+    private static final int USER_1 = 110;
+    private static final int USER_2 = 111;
+    private static final int UID_A_1 = 11011111;
+    private static final int UID_A_2 = 11111111;
+    private static final int UID_B_1 = 11022222;
+    private static final int UID_B_2 = 11122222;
+
+    @Before
+    public void setup() {
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
+
+        when(mMockUserManagerInternal.getUserIds()).thenReturn(new int[]{USER_1, USER_2});
+        when(mMockPackageManagerInternal.getPackageUid(PKG_A, 0, USER_1)).thenReturn(UID_A_1);
+        when(mMockPackageManagerInternal.getPackageUid(PKG_A, 0, USER_2)).thenReturn(UID_A_2);
+        when(mMockPackageManagerInternal.getPackageUid(PKG_B, 0, USER_1)).thenReturn(UID_B_1);
+        when(mMockPackageManagerInternal.getPackageUid(PKG_B, 0, USER_2)).thenReturn(UID_B_2);
+        when(mMockPackageManagerInternal.getPackageUid(PKG_NOT_INSTALLED, 0, USER_1)).thenReturn(
+                INVALID_UID);
+        when(mMockPackageManagerInternal.getPackageUid(PKG_NOT_INSTALLED, 0, USER_2)).thenReturn(
+                INVALID_UID);
+
+        mSmallAreaDetectionController = spy(new SmallAreaDetectionController(
+                new ContextWrapper(ApplicationProvider.getApplicationContext()),
+                DeviceConfigInterface.REAL));
+        doNothing().when(mSmallAreaDetectionController).updateSmallAreaDetection(any(), any());
+    }
+
+    @Test
+    public void testUpdateAllowlist_validProperty() {
+        final String property = PKG_A + ":" + THRESHOLD_A + "," + PKG_B + ":" + THRESHOLD_B;
+        mSmallAreaDetectionController.updateAllowlist(property);
+
+        final int[] resultUidArray = {UID_A_1, UID_B_1, UID_A_2, UID_B_2};
+        final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_B, THRESHOLD_A, THRESHOLD_B};
+        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+                eq(resultThresholdArray));
+    }
+
+    @Test
+    public void testUpdateAllowlist_includeInvalidRow() {
+        final String property = PKG_A + "," + PKG_B + ":" + THRESHOLD_B;
+        mSmallAreaDetectionController.updateAllowlist(property);
+
+        final int[] resultUidArray = {UID_B_1, UID_B_2};
+        final float[] resultThresholdArray = {THRESHOLD_B, THRESHOLD_B};
+        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+                eq(resultThresholdArray));
+    }
+
+    @Test
+    public void testUpdateAllowlist_includeNotInstalledPkg() {
+        final String property =
+                PKG_A + ":" + THRESHOLD_A + "," + PKG_NOT_INSTALLED + ":" + THRESHOLD_B;
+        mSmallAreaDetectionController.updateAllowlist(property);
+
+        final int[] resultUidArray = {UID_A_1, UID_A_2};
+        final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_A};
+        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+                eq(resultThresholdArray));
+    }
+
+    @Test
+    public void testUpdateAllowlist_invalidProperty() {
+        final String property = PKG_A;
+        mSmallAreaDetectionController.updateAllowlist(property);
+
+        verify(mSmallAreaDetectionController, never()).updateSmallAreaDetection(any(), any());
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ArchiveManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ArchiveManagerTest.java
deleted file mode 100644
index a8b0a7b..0000000
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ArchiveManagerTest.java
+++ /dev/null
@@ -1,230 +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.server.pm;
-
-import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.IntentSender;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.VersionedPackage;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Process;
-import android.os.UserHandle;
-import android.platform.test.annotations.Presubmit;
-import android.text.TextUtils;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.pm.pkg.ArchiveState;
-import com.android.server.pm.pkg.PackageStateInternal;
-
-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.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class ArchiveManagerTest {
-
-    private static final String PACKAGE = "com.example";
-    private static final String CALLER_PACKAGE = "com.vending";
-
-    @Rule
-    public final MockSystemRule mMockSystem = new MockSystemRule();
-
-    @Mock
-    private IntentSender mIntentSender;
-    @Mock
-    private Computer mComputer;
-    @Mock
-    private Context mContext;
-    @Mock
-    private LauncherApps mLauncherApps;
-    @Mock
-    private PackageInstallerService mInstallerService;
-    @Mock
-    private PackageStateInternal mPackageState;
-
-    private final InstallSource mInstallSource =
-            InstallSource.create(
-                    CALLER_PACKAGE,
-                    CALLER_PACKAGE,
-                    CALLER_PACKAGE,
-                    Binder.getCallingUid(),
-                    CALLER_PACKAGE,
-                    /* installerAttributionTag= */ null,
-                    /* packageSource= */ 0);
-
-    private final List<LauncherActivityInfo> mLauncherActivityInfos = createLauncherActivities();
-
-    private PackageSetting mPackageSetting;
-
-    private PackageManagerService mPm;
-    private ArchiveManager mArchiveManager;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        mMockSystem.system().stageNominalSystemState();
-        when(mMockSystem.mocks().getInjector().getPackageInstallerService()).thenReturn(
-                mInstallerService);
-        mPm = spy(new PackageManagerService(mMockSystem.mocks().getInjector(),
-                /* factoryTest= */false,
-                MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint,
-                /* isEngBuild= */ false,
-                /* isUserDebugBuild= */false,
-                Build.VERSION_CODES.CUR_DEVELOPMENT,
-                Build.VERSION.INCREMENTAL));
-
-        when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
-                mPackageState);
-        when(mPackageState.getPackageName()).thenReturn(PACKAGE);
-        when(mPackageState.getInstallSource()).thenReturn(mInstallSource);
-        mPackageSetting = createBasicPackageSetting();
-        when(mMockSystem.mocks().getSettings().getPackageLPr(eq(PACKAGE))).thenReturn(
-                mPackageSetting);
-        when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
-        when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(
-                mLauncherActivityInfos);
-        doReturn(mComputer).when(mPm).snapshotComputer();
-        when(mComputer.getNameForUid(eq(Binder.getCallingUid()))).thenReturn(CALLER_PACKAGE);
-        mArchiveManager = new ArchiveManager(mContext, mPm);
-    }
-
-    @Test
-    public void archiveApp_callerPackageNameIncorrect() {
-        Exception e = assertThrows(
-                SecurityException.class,
-                () -> mArchiveManager.archiveApp(PACKAGE, "different", UserHandle.CURRENT,
-                        mIntentSender)
-        );
-        assertThat(e).hasMessageThat().isEqualTo(
-                String.format(
-                        "The callerPackageName %s set by the caller doesn't match the "
-                                + "caller's own package name %s.",
-                        "different",
-                        CALLER_PACKAGE));
-    }
-
-    @Test
-    public void archiveApp_packageNotInstalled() {
-        when(mMockSystem.mocks().getSettings().getPackageLPr(eq(PACKAGE))).thenReturn(
-                null);
-
-        Exception e = assertThrows(
-                PackageManager.NameNotFoundException.class,
-                () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT,
-                        mIntentSender)
-        );
-        assertThat(e).hasMessageThat().isEqualTo(String.format("Package %s not found.", PACKAGE));
-    }
-
-    @Test
-    public void archiveApp_packageNotInstalledForUser() {
-        mPackageSetting.modifyUserState(UserHandle.CURRENT.getIdentifier()).setInstalled(false);
-
-        Exception e = assertThrows(
-                PackageManager.NameNotFoundException.class,
-                () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT,
-                        mIntentSender)
-        );
-        assertThat(e).hasMessageThat().isEqualTo(String.format("Package %s not found.", PACKAGE));
-    }
-
-    @Test
-    public void archiveApp_noInstallerFound() {
-        InstallSource otherInstallSource =
-                InstallSource.create(
-                        CALLER_PACKAGE,
-                        CALLER_PACKAGE,
-                        /* installerPackageName= */ null,
-                        Binder.getCallingUid(),
-                        /* updateOwnerPackageName= */ null,
-                        /* installerAttributionTag= */ null,
-                        /* packageSource= */ 0);
-        when(mPackageState.getInstallSource()).thenReturn(otherInstallSource);
-
-        Exception e = assertThrows(
-                SecurityException.class,
-                () -> mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, Process.myUserHandle(),
-                        mIntentSender)
-        );
-        assertThat(e).hasMessageThat().isEqualTo(
-                TextUtils.formatSimple("No installer found to archive app %s.",
-                        PACKAGE));
-    }
-
-    @Test
-    public void archiveApp_success() throws PackageManager.NameNotFoundException {
-        List<ArchiveState.ArchiveActivityInfo> activityInfos = new ArrayList<>();
-        for (LauncherActivityInfo mainActivity : createLauncherActivities()) {
-            // TODO(b/278553670) Extract and store launcher icons
-            ArchiveState.ArchiveActivityInfo activityInfo = new ArchiveState.ArchiveActivityInfo(
-                    mainActivity.getLabel().toString(),
-                    Path.of("/TODO"), null);
-            activityInfos.add(activityInfo);
-        }
-
-        mArchiveManager.archiveApp(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT, mIntentSender);
-        verify(mInstallerService).uninstall(
-                eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)),
-                eq(CALLER_PACKAGE), eq(DELETE_KEEP_DATA), eq(mIntentSender),
-                eq(UserHandle.CURRENT.getIdentifier()));
-        assertThat(mPackageSetting.readUserState(
-                UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo(
-                new ArchiveState(activityInfos, CALLER_PACKAGE));
-    }
-
-    private static List<LauncherActivityInfo> createLauncherActivities() {
-        LauncherActivityInfo activity1 = mock(LauncherActivityInfo.class);
-        when(activity1.getLabel()).thenReturn("activity1");
-        LauncherActivityInfo activity2 = mock(LauncherActivityInfo.class);
-        when(activity2.getLabel()).thenReturn("activity2");
-        return List.of(activity1, activity2);
-    }
-
-    private PackageSetting createBasicPackageSetting() {
-        return new PackageSettingBuilder()
-                .setName(PACKAGE).setCodePath("/data/app/" + PACKAGE + "-randompath")
-                .setInstallState(UserHandle.CURRENT.getIdentifier(), /* installed= */ true)
-                .build();
-    }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 3c75332..e578ea3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -567,9 +567,8 @@
 
     @Throws(Exception::class)
     private fun stageInstantAppResolverScan() {
-        whenever(mocks.resources.getStringArray(R.array.config_ephemeralResolverPackage)) {
-            arrayOf("com.android.test.ephemeral.resolver")
-        }
+        doReturn(arrayOf("com.android.test.ephemeral.resolver"))
+            .whenever(mocks.resources).getStringArray(R.array.config_ephemeralResolverPackage)
         stageScanNewPackage("com.android.test.ephemeral.resolver",
                 1L, getPartitionFromFlag(PackageManagerService.SCAN_AS_PRODUCT).privAppFolder,
                 withPackage = { pkg: PackageImpl ->
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
new file mode 100644
index 0000000..80576a6
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
+import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageArchiver;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.ParcelableException;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.text.TextUtils;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.pm.pkg.ArchiveState;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageUserStateImpl;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class PackageArchiverServiceTest {
+
+    private static final String PACKAGE = "com.example";
+    private static final String CALLER_PACKAGE = "com.caller";
+    private static final String INSTALLER_PACKAGE = "com.installer";
+
+    @Rule
+    public final MockSystemRule mMockSystem = new MockSystemRule();
+
+    @Mock
+    private IntentSender mIntentSender;
+    @Mock
+    private Computer mComputer;
+    @Mock
+    private Context mContext;
+    @Mock
+    private LauncherApps mLauncherApps;
+    @Mock
+    private PackageInstallerService mInstallerService;
+    @Mock
+    private PackageStateInternal mPackageState;
+
+    private final InstallSource mInstallSource =
+            InstallSource.create(
+                    INSTALLER_PACKAGE,
+                    INSTALLER_PACKAGE,
+                    INSTALLER_PACKAGE,
+                    Binder.getCallingUid(),
+                    INSTALLER_PACKAGE,
+                    /* installerAttributionTag= */ null,
+                    /* packageSource= */ 0);
+
+    private final List<LauncherActivityInfo> mLauncherActivityInfos = createLauncherActivities();
+
+    private final int mUserId = UserHandle.CURRENT.getIdentifier();
+
+    private PackageUserStateImpl mUserState;
+
+    private PackageSetting mPackageSetting;
+
+    private PackageArchiverService mArchiveService;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mMockSystem.system().stageNominalSystemState();
+        when(mMockSystem.mocks().getInjector().getPackageInstallerService()).thenReturn(
+                mInstallerService);
+        PackageManagerService pm = spy(new PackageManagerService(mMockSystem.mocks().getInjector(),
+                /* factoryTest= */false,
+                MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint,
+                /* isEngBuild= */ false,
+                /* isUserDebugBuild= */false,
+                Build.VERSION_CODES.CUR_DEVELOPMENT,
+                Build.VERSION.INCREMENTAL));
+
+        when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
+                mPackageState);
+        when(mComputer.getPackageStateFiltered(eq(INSTALLER_PACKAGE), anyInt(),
+                anyInt())).thenReturn(mock(PackageStateInternal.class));
+        when(mPackageState.getPackageName()).thenReturn(PACKAGE);
+        when(mPackageState.getInstallSource()).thenReturn(mInstallSource);
+        mPackageSetting = createBasicPackageSetting();
+        when(mMockSystem.mocks().getSettings().getPackageLPr(eq(PACKAGE))).thenReturn(
+                mPackageSetting);
+        mUserState = new PackageUserStateImpl().setInstalled(true);
+        mPackageSetting.setUserState(mUserId, mUserState);
+        when(mPackageState.getUserStateOrDefault(eq(mUserId))).thenReturn(mUserState);
+        when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
+        when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(
+                mLauncherActivityInfos);
+        doReturn(mComputer).when(pm).snapshotComputer();
+        when(mComputer.getPackageUid(eq(CALLER_PACKAGE), eq(0L), eq(mUserId))).thenReturn(
+                Binder.getCallingUid());
+        mArchiveService = new PackageArchiverService(mContext, pm);
+    }
+
+    @Test
+    public void archiveApp_callerPackageNameIncorrect() {
+        Exception e = assertThrows(
+                SecurityException.class,
+                () -> mArchiveService.requestArchive(PACKAGE, "different", mIntentSender,
+                        UserHandle.CURRENT));
+        assertThat(e).hasMessageThat().isEqualTo(
+                String.format(
+                        "The UID %s of callerPackageName set by the caller doesn't match the "
+                                + "caller's actual UID %s.",
+                        0,
+                        Binder.getCallingUid()));
+    }
+
+    @Test
+    public void archiveApp_packageNotInstalled() {
+        when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
+                null);
+
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo(
+                String.format("Package %s not found.", PACKAGE));
+    }
+
+    @Test
+    public void archiveApp_packageNotInstalledForUser() {
+        mPackageSetting.modifyUserState(UserHandle.CURRENT.getIdentifier()).setInstalled(false);
+
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo(
+                String.format("Package %s not found.", PACKAGE));
+    }
+
+    @Test
+    public void archiveApp_noInstallerFound() {
+        InstallSource otherInstallSource =
+                InstallSource.create(
+                        CALLER_PACKAGE,
+                        CALLER_PACKAGE,
+                        /* installerPackageName= */ null,
+                        Binder.getCallingUid(),
+                        /* updateOwnerPackageName= */ null,
+                        /* installerAttributionTag= */ null,
+                        /* packageSource= */ 0);
+        when(mPackageState.getInstallSource()).thenReturn(otherInstallSource);
+
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found");
+    }
+
+    @Test
+    public void archiveApp_noMainActivities() {
+        when(mLauncherApps.getActivityList(eq(PACKAGE), eq(UserHandle.CURRENT))).thenReturn(
+                List.of());
+
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo(
+                TextUtils.formatSimple("The app %s does not have a main activity.", PACKAGE));
+    }
+
+    @Test
+    public void archiveApp_success() {
+        mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT);
+
+        verify(mInstallerService).uninstall(
+                eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)),
+                eq(CALLER_PACKAGE), eq(DELETE_KEEP_DATA), eq(mIntentSender),
+                eq(UserHandle.CURRENT.getIdentifier()));
+        assertThat(mPackageSetting.readUserState(
+                UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo(
+                createArchiveState());
+    }
+
+    @Test
+    public void unarchiveApp_callerPackageNameIncorrect() {
+        mUserState.setArchiveState(createArchiveState()).setInstalled(false);
+
+        Exception e = assertThrows(
+                SecurityException.class,
+                () -> mArchiveService.requestUnarchive(PACKAGE, "different",
+                        UserHandle.CURRENT));
+        assertThat(e).hasMessageThat().isEqualTo(
+                String.format(
+                        "The UID %s of callerPackageName set by the caller doesn't match the "
+                                + "caller's actual UID %s.",
+                        0,
+                        Binder.getCallingUid()));
+    }
+
+    @Test
+    public void unarchiveApp_packageNotInstalled() {
+        mUserState.setArchiveState(createArchiveState()).setInstalled(false);
+        when(mComputer.getPackageStateFiltered(eq(PACKAGE), anyInt(), anyInt())).thenReturn(
+                null);
+
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestUnarchive(PACKAGE, CALLER_PACKAGE,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo(
+                String.format("Package %s not found.", PACKAGE));
+    }
+
+    @Test
+    public void unarchiveApp_notArchived() {
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestUnarchive(PACKAGE, CALLER_PACKAGE,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo(
+                String.format("Package %s is not currently archived.", PACKAGE));
+    }
+
+    @Test
+    public void unarchiveApp_noInstallerFound() {
+        mUserState.setArchiveState(createArchiveState());
+        InstallSource otherInstallSource =
+                InstallSource.create(
+                        CALLER_PACKAGE,
+                        CALLER_PACKAGE,
+                        /* installerPackageName= */ null,
+                        Binder.getCallingUid(),
+                        /* updateOwnerPackageName= */ null,
+                        /* installerAttributionTag= */ null,
+                        /* packageSource= */ 0);
+        when(mPackageState.getInstallSource()).thenReturn(otherInstallSource);
+
+        Exception e = assertThrows(
+                ParcelableException.class,
+                () -> mArchiveService.requestUnarchive(PACKAGE, CALLER_PACKAGE,
+                        UserHandle.CURRENT));
+        assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
+        assertThat(e.getCause()).hasMessageThat().isEqualTo(
+                String.format("No installer found to unarchive app %s.", PACKAGE));
+    }
+
+    @Test
+    public void unarchiveApp_success() {
+        mUserState.setArchiveState(createArchiveState()).setInstalled(false);
+
+        mArchiveService.requestUnarchive(PACKAGE, CALLER_PACKAGE, UserHandle.CURRENT);
+        mMockSystem.mocks().getHandler().flush();
+
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext).sendOrderedBroadcastAsUser(
+                intentCaptor.capture(),
+                eq(UserHandle.CURRENT),
+                /* receiverPermission = */ isNull(),
+                eq(AppOpsManager.OP_NONE),
+                any(Bundle.class),
+                /* resultReceiver= */ isNull(),
+                /* scheduler= */ isNull(),
+                /* initialCode= */ eq(0),
+                /* initialData= */ isNull(),
+                /* initialExtras= */ isNull());
+        Intent intent = intentCaptor.getValue();
+        assertThat(intent.getFlags() & FLAG_RECEIVER_FOREGROUND).isNotEqualTo(0);
+        assertThat(intent.getStringExtra(PackageArchiver.EXTRA_UNARCHIVE_PACKAGE_NAME)).isEqualTo(
+                PACKAGE);
+        assertThat(
+                intent.getBooleanExtra(PackageArchiver.EXTRA_UNARCHIVE_ALL_USERS, true)).isFalse();
+        assertThat(intent.getPackage()).isEqualTo(INSTALLER_PACKAGE);
+    }
+
+    private static ArchiveState createArchiveState() {
+        List<ArchiveState.ArchiveActivityInfo> activityInfos = new ArrayList<>();
+        for (LauncherActivityInfo mainActivity : createLauncherActivities()) {
+            // TODO(b/278553670) Extract and store launcher icons
+            ArchiveState.ArchiveActivityInfo activityInfo = new ArchiveState.ArchiveActivityInfo(
+                    mainActivity.getLabel().toString(),
+                    Path.of("/TODO"), null);
+            activityInfos.add(activityInfo);
+        }
+        return new ArchiveState(activityInfos, INSTALLER_PACKAGE);
+    }
+
+    private static List<LauncherActivityInfo> createLauncherActivities() {
+        LauncherActivityInfo activity1 = mock(LauncherActivityInfo.class);
+        when(activity1.getLabel()).thenReturn("activity1");
+        LauncherActivityInfo activity2 = mock(LauncherActivityInfo.class);
+        when(activity2.getLabel()).thenReturn("activity2");
+        return List.of(activity1, activity2);
+    }
+
+    private PackageSetting createBasicPackageSetting() {
+        return new PackageSettingBuilder()
+                .setName(PACKAGE).setCodePath("/data/app/" + PACKAGE + "-randompath")
+                .setInstallState(UserHandle.CURRENT.getIdentifier(), /* installed= */ true)
+                .build();
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
index d99af77..e5fae49 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageFreezerTest.kt
@@ -88,7 +88,8 @@
 
     @Test
     fun freezePackage() {
-        val freezer = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms, TEST_EXIT_REASON)
+        val freezer = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
+                TEST_EXIT_REASON, null /* request */)
         verify(pms, times(1))
             .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON),
                     eq(TEST_EXIT_REASON))
@@ -104,9 +105,9 @@
     @Test
     fun freezePackage_twice() {
         val freezer1 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
-                TEST_EXIT_REASON)
+                TEST_EXIT_REASON, null  /* request */)
         val freezer2 = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
-                TEST_EXIT_REASON)
+                TEST_EXIT_REASON, null  /* request */)
         verify(pms, times(2))
             .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON),
                     eq(TEST_EXIT_REASON))
@@ -127,7 +128,7 @@
     @Test
     fun freezePackage_withoutClosing() {
         var freezer: PackageFreezer? = PackageFreezer(TEST_PACKAGE, TEST_USER_ID, TEST_REASON, pms,
-                TEST_EXIT_REASON)
+                TEST_EXIT_REASON, null  /* request */)
         verify(pms, times(1))
             .killApplication(eq(TEST_PACKAGE), any(), eq(TEST_USER_ID), eq(TEST_REASON),
                     eq(TEST_EXIT_REASON))
diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
index 20cfd59..dc04b6a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/CameraPrivacyLightControllerTest.java
@@ -24,10 +24,12 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -43,14 +45,13 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.permission.PermissionManager;
-import android.util.ArraySet;
+import android.testing.TestableLooper;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.R;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -62,24 +63,19 @@
 import java.util.List;
 import java.util.Random;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 public class CameraPrivacyLightControllerTest {
+    private int[] mDefaultColors = {0, 1, 2};
+    private int[] mDefaultAlsThresholdsLux = {10, 50};
+    private int mDefaultAlsAveragingIntervalMillis = 5000;
 
-    private int mDayColor = 1;
-    private int mNightColor = 0;
-    private int mCameraPrivacyLightAlsAveragingIntervalMillis = 5000;
-    private int mCameraPrivacyLightAlsNightThreshold = (int) getLightSensorValue(15);
+    private TestableLooper mTestableLooper;
 
     private MockitoSession mMockitoSession;
 
     @Mock
-    private Context mContext;
-
-    @Mock
-    private Resources mResources;
-
-    @Mock
     private LightsManager mLightsManager;
 
     @Mock
@@ -103,11 +99,64 @@
     private ArgumentCaptor<SensorEventListener> mLightSensorListenerCaptor =
             ArgumentCaptor.forClass(SensorEventListener.class);
 
-    private Set<String> mExemptedPackages = new ArraySet<>();
-    private List<Light> mLights = new ArrayList<>();
+    private Set<String> mExemptedPackages;
+    private List<Light> mLights;
 
     private int mNextLightId = 1;
 
+    public CameraPrivacyLightController prepareDefaultCameraPrivacyLightController() {
+        return prepareDefaultCameraPrivacyLightController(List.of(getNextLight(true)));
+    }
+
+    public CameraPrivacyLightController prepareDefaultCameraPrivacyLightController(
+            List<Light> lights) {
+        return prepareCameraPrivacyLightController(lights, Set.of(), true, mDefaultColors,
+                mDefaultAlsThresholdsLux, mDefaultAlsAveragingIntervalMillis);
+    }
+
+    public CameraPrivacyLightController prepareCameraPrivacyLightController(List<Light> lights,
+            Set<String> exemptedPackages, boolean hasLightSensor, int[] lightColors,
+            int[] alsThresholds, int averagingInterval) {
+        Looper looper = Looper.myLooper();
+        if (looper == null) {
+            Looper.prepare();
+            looper = Looper.myLooper();
+        }
+        if (mTestableLooper == null) {
+            try {
+                mTestableLooper = new TestableLooper(looper);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        Context context = mock(Context.class);
+        Resources resources = mock(Resources.class);
+        doReturn(resources).when(context).getResources();
+        doReturn(lightColors).when(resources).getIntArray(R.array.config_cameraPrivacyLightColors);
+        doReturn(alsThresholds).when(resources)
+                .getIntArray(R.array.config_cameraPrivacyLightAlsLuxThresholds);
+        doReturn(averagingInterval).when(resources)
+                .getInteger(R.integer.config_cameraPrivacyLightAlsAveragingIntervalMillis);
+
+        doReturn(mLightsManager).when(context).getSystemService(LightsManager.class);
+        doReturn(mAppOpsManager).when(context).getSystemService(AppOpsManager.class);
+        doReturn(mSensorManager).when(context).getSystemService(SensorManager.class);
+
+        mLights = lights;
+        mExemptedPackages = exemptedPackages;
+        doReturn(mLights).when(mLightsManager).getLights();
+        doReturn(mLightsSession).when(mLightsManager).openSession(anyInt());
+        if (!hasLightSensor) {
+            mLightSensor = null;
+        }
+        doReturn(mLightSensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
+        doReturn(exemptedPackages)
+                .when(() -> PermissionManager.getIndicatorExemptedPackages(any()));
+
+        return new CameraPrivacyLightController(context, looper);
+    }
+
     @Before
     public void setUp() {
         mMockitoSession = ExtendedMockito.mockitoSession()
@@ -115,49 +164,33 @@
                 .strictness(Strictness.WARN)
                 .spyStatic(PermissionManager.class)
                 .startMocking();
-
-        doReturn(mDayColor).when(mContext).getColor(R.color.camera_privacy_light_day);
-        doReturn(mNightColor).when(mContext).getColor(R.color.camera_privacy_light_night);
-
-        doReturn(mResources).when(mContext).getResources();
-        doReturn(mCameraPrivacyLightAlsAveragingIntervalMillis).when(mResources)
-                .getInteger(R.integer.config_cameraPrivacyLightAlsAveragingIntervalMillis);
-        doReturn(mCameraPrivacyLightAlsNightThreshold).when(mResources)
-                .getInteger(R.integer.config_cameraPrivacyLightAlsNightThreshold);
-
-        doReturn(mLightsManager).when(mContext).getSystemService(LightsManager.class);
-        doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
-        doReturn(mSensorManager).when(mContext).getSystemService(SensorManager.class);
-
-        doReturn(mLights).when(mLightsManager).getLights();
-        doReturn(mLightsSession).when(mLightsManager).openSession(anyInt());
-        doReturn(mLightSensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
-
-        doReturn(mExemptedPackages)
-                .when(() -> PermissionManager.getIndicatorExemptedPackages(any()));
     }
 
     @After
     public void tearDown() {
-        mExemptedPackages.clear();
-        mLights.clear();
-
         mMockitoSession.finishMocking();
     }
 
     @Test
+    public void testNoInteractionsWithServicesIfNoColorsSpecified() {
+        prepareCameraPrivacyLightController(List.of(getNextLight(true)), Collections.EMPTY_SET,
+                true, new int[0], mDefaultAlsThresholdsLux, mDefaultAlsAveragingIntervalMillis);
+
+        verifyZeroInteractions(mLightsManager);
+        verifyZeroInteractions(mAppOpsManager);
+        verifyZeroInteractions(mSensorManager);
+    }
+
+    @Test
     public void testAppsOpsListenerNotRegisteredWithoutCameraLights() {
-        mLights.add(getNextLight(false));
-        createCameraPrivacyLightController();
+        prepareDefaultCameraPrivacyLightController(List.of(getNextLight(false)));
 
         verify(mAppOpsManager, times(0)).startWatchingActive(any(), any(), any());
     }
 
     @Test
     public void testAppsOpsListenerRegisteredWithCameraLight() {
-        mLights.add(getNextLight(true));
-
-        createCameraPrivacyLightController();
+        prepareDefaultCameraPrivacyLightController();
 
         verify(mAppOpsManager, times(1)).startWatchingActive(any(), any(), any());
     }
@@ -165,11 +198,12 @@
     @Test
     public void testAllCameraLightsAreRequestedOnOpActive() {
         Random r = new Random(0);
+        List<Light> lights = new ArrayList<>();
         for (int i = 0; i < 30; i++) {
-            mLights.add(getNextLight(r.nextBoolean()));
+            lights.add(getNextLight(r.nextBoolean()));
         }
 
-        createCameraPrivacyLightController();
+        prepareDefaultCameraPrivacyLightController(lights);
 
         // Verify no session has been opened at this point.
         verify(mLightsManager, times(0)).openSession(anyInt());
@@ -181,8 +215,6 @@
         verify(mLightsManager, times(1)).openSession(anyInt());
 
         verify(mLightsSession).requestLights(mLightsRequestCaptor.capture());
-        assertEquals("requestLights() not invoked exactly once",
-                1, mLightsRequestCaptor.getAllValues().size());
 
         List<Integer> expectedCameraLightIds = mLights.stream()
                 .filter(l -> l.getType() == Light.LIGHT_TYPE_CAMERA)
@@ -199,40 +231,25 @@
 
     @Test
     public void testWillOnlyOpenOnceWhenTwoPackagesStartOp() {
-        mLights.add(getNextLight(true));
-
-        createCameraPrivacyLightController();
-
-        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
-
-        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
-        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+        prepareDefaultCameraPrivacyLightController();
+        notifyCamOpChanged(10101, "pkg1", true);
         verify(mLightsManager, times(1)).openSession(anyInt());
-        listener.onOpActiveChanged(OPSTR_CAMERA, 10102, "pkg2", true);
+        notifyCamOpChanged(10102, "pkg2", true);
         verify(mLightsManager, times(1)).openSession(anyInt());
     }
 
     @Test
     public void testWillCloseOnFinishOp() {
-        mLights.add(getNextLight(true));
-
-        createCameraPrivacyLightController();
-
-        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
-
-        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
-        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
-
+        prepareDefaultCameraPrivacyLightController();
+        notifyCamOpChanged(10101, "pkg1", true);
         verify(mLightsSession, times(0)).close();
-        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", false);
+        notifyCamOpChanged(10101, "pkg1", false);
         verify(mLightsSession, times(1)).close();
     }
 
     @Test
     public void testWillCloseOnFinishOpForAllPackages() {
-        mLights.add(getNextLight(true));
-
-        createCameraPrivacyLightController();
+        prepareDefaultCameraPrivacyLightController();
 
         int numUids = 100;
         List<Integer> uids = new ArrayList<>(numUids);
@@ -240,64 +257,52 @@
             uids.add(10001 + i);
         }
 
-        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
-
-        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
-
         for (int i = 0; i < numUids; i++) {
-            listener.onOpActiveChanged(OPSTR_CAMERA, uids.get(i), "pkg" + (int) uids.get(i), true);
+            notifyCamOpChanged(uids.get(i), "pkg" + (int) uids.get(i), true);
         }
 
         // Change the order which their ops are finished
         Collections.shuffle(uids, new Random(0));
 
         for (int i = 0; i < numUids - 1; i++) {
-            listener.onOpActiveChanged(OPSTR_CAMERA, uids.get(i), "pkg" + (int) uids.get(i), false);
+            notifyCamOpChanged(uids.get(i), "pkg" + (int) uids.get(i), false);
         }
 
         verify(mLightsSession, times(0)).close();
         int lastUid = uids.get(numUids - 1);
-        listener.onOpActiveChanged(OPSTR_CAMERA, lastUid, "pkg" + lastUid, false);
+        notifyCamOpChanged(lastUid, "pkg" + lastUid, false);
         verify(mLightsSession, times(1)).close();
     }
 
     @Test
     public void testWontOpenForExemptedPackage() {
-        mLights.add(getNextLight(true));
-        mExemptedPackages.add("pkg1");
+        String exemptPackage = "pkg1";
+        prepareCameraPrivacyLightController(List.of(getNextLight(true)),
+                Set.of(exemptPackage), true, mDefaultColors, mDefaultAlsThresholdsLux,
+                mDefaultAlsAveragingIntervalMillis);
 
-        createCameraPrivacyLightController();
-
-        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
-
-        AppOpsManager.OnOpActiveChangedListener listener = mAppOpsListenerCaptor.getValue();
-        listener.onOpActiveChanged(OPSTR_CAMERA, 10101, "pkg1", true);
+        notifyCamOpChanged(10101, exemptPackage, true);
         verify(mLightsManager, times(0)).openSession(anyInt());
     }
 
     @Test
     public void testNoLightSensor() {
-        mLights.add(getNextLight(true));
-        doReturn(null).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
-
-        createCameraPrivacyLightController();
+        prepareCameraPrivacyLightController(List.of(getNextLight(true)),
+                Set.of(), true, mDefaultColors, mDefaultAlsThresholdsLux,
+                mDefaultAlsAveragingIntervalMillis);
 
         openCamera();
 
         verify(mLightsSession).requestLights(mLightsRequestCaptor.capture());
         LightsRequest lightsRequest = mLightsRequestCaptor.getValue();
         for (LightState lightState : lightsRequest.getLightStates()) {
-            assertEquals(mDayColor, lightState.getColor());
+            assertEquals(mDefaultColors[mDefaultColors.length - 1], lightState.getColor());
         }
     }
 
     @Test
     public void testALSListenerNotRegisteredUntilCameraIsOpened() {
-        mLights.add(getNextLight(true));
-        Sensor sensor = mock(Sensor.class);
-        doReturn(sensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
-
-        CameraPrivacyLightController cplc = createCameraPrivacyLightController();
+        prepareDefaultCameraPrivacyLightController();
 
         verify(mSensorManager, never()).registerListener(any(SensorEventListener.class),
                 any(Sensor.class), anyInt(), any(Handler.class));
@@ -307,113 +312,44 @@
         verify(mSensorManager, times(1)).registerListener(mLightSensorListenerCaptor.capture(),
                 any(Sensor.class), anyInt(), any(Handler.class));
 
-        mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10001, "pkg", false);
+        notifyCamOpChanged(10001, "pkg", false);
         verify(mSensorManager, times(1)).unregisterListener(mLightSensorListenerCaptor.getValue());
     }
 
-    @Ignore
     @Test
-    public void testDayColor() {
-        testBrightnessToColor(20, mDayColor);
-    }
-
-    @Ignore
-    @Test
-    public void testNightColor() {
-        testBrightnessToColor(10, mNightColor);
-    }
-
-    private void testBrightnessToColor(int brightnessValue, int color) {
-        mLights.add(getNextLight(true));
-        Sensor sensor = mock(Sensor.class);
-        doReturn(sensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
-
-        CameraPrivacyLightController cplc = createCameraPrivacyLightController();
+    public void testAlsThresholds() {
+        CameraPrivacyLightController cplc = prepareDefaultCameraPrivacyLightController();
+        long elapsedTime = 0;
         cplc.setElapsedRealTime(0);
-
         openCamera();
+        for (int i = 0; i < mDefaultColors.length; i++) {
+            int expectedColor = mDefaultColors[i];
+            int alsLuxValue = i
+                    == mDefaultAlsThresholdsLux.length
+                    ? mDefaultAlsThresholdsLux[i - 1] : mDefaultAlsThresholdsLux[i] - 1;
 
-        verify(mSensorManager).registerListener(mLightSensorListenerCaptor.capture(),
-                any(Sensor.class), anyInt(), any(Handler.class));
-        SensorEventListener sensorListener = mLightSensorListenerCaptor.getValue();
-        float[] sensorEventValues = new float[1];
-        SensorEvent sensorEvent = new SensorEvent(sensor, 0, 0, sensorEventValues);
+            notifySensorEvent(cplc, elapsedTime, alsLuxValue);
+            elapsedTime += mDefaultAlsAveragingIntervalMillis + 1;
+            notifySensorEvent(cplc, elapsedTime, alsLuxValue);
 
-        sensorEventValues[0] = getLightSensorValue(brightnessValue);
-        sensorListener.onSensorChanged(sensorEvent);
-
-        verify(mLightsSession, atLeastOnce()).requestLights(mLightsRequestCaptor.capture());
-        for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
-            assertEquals(color, lightState.getColor());
+            verify(mLightsSession, atLeastOnce()).requestLights(mLightsRequestCaptor.capture());
+            for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
+                assertEquals(expectedColor, lightState.getColor());
+            }
         }
     }
 
-    @Ignore
-    @Test
-    public void testDayToNightTransistion() {
-        mLights.add(getNextLight(true));
-        Sensor sensor = mock(Sensor.class);
-        doReturn(sensor).when(mSensorManager).getDefaultSensor(Sensor.TYPE_LIGHT);
-
-        CameraPrivacyLightController cplc = createCameraPrivacyLightController();
-        cplc.setElapsedRealTime(0);
-
-        openCamera();
-        // There will be an initial call at brightness 0
-        verify(mLightsSession, times(1)).requestLights(any(LightsRequest.class));
-
-        verify(mSensorManager).registerListener(mLightSensorListenerCaptor.capture(),
-                any(Sensor.class), anyInt(), any(Handler.class));
-        SensorEventListener sensorListener = mLightSensorListenerCaptor.getValue();
-
-        onSensorEvent(cplc, sensorListener, sensor, 0, 20);
-
-        // 5 sec avg = 20
-        onSensorEvent(cplc, sensorListener, sensor, 5000, 30);
-
-        verify(mLightsSession, times(2)).requestLights(mLightsRequestCaptor.capture());
-        for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
-            assertEquals(mDayColor, lightState.getColor());
-        }
-
-        // 5 sec avg = 22
-
-        onSensorEvent(cplc, sensorListener, sensor, 6000, 10);
-
-        // 5 sec avg = 18
-
-        onSensorEvent(cplc, sensorListener, sensor, 8000, 5);
-
-        // Should have always been day
-        verify(mLightsSession, times(2)).requestLights(mLightsRequestCaptor.capture());
-        for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
-            assertEquals(mDayColor, lightState.getColor());
-        }
-
-        // 5 sec avg = 12
-
-        onSensorEvent(cplc, sensorListener, sensor, 10000, 5);
-
-        // Should now be night
-        verify(mLightsSession, times(3)).requestLights(mLightsRequestCaptor.capture());
-        for (LightState lightState : mLightsRequestCaptor.getValue().getLightStates()) {
-            assertEquals(mNightColor, lightState.getColor());
-        }
+    private void notifyCamOpChanged(int uid, String pkg, boolean active) {
+        verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
+        mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, uid, pkg, active);
     }
 
-    private void onSensorEvent(CameraPrivacyLightController cplc,
-            SensorEventListener sensorListener, Sensor sensor, long timestamp, int value) {
+    private void notifySensorEvent(CameraPrivacyLightController cplc, long timestamp, int value) {
         cplc.setElapsedRealTime(timestamp);
-        sensorListener.onSensorChanged(new SensorEvent(sensor, 0, timestamp,
-                new float[] {getLightSensorValue(value)}));
-    }
-
-    // Use the test thread so that the test is deterministic
-    private CameraPrivacyLightController createCameraPrivacyLightController() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-        return new CameraPrivacyLightController(mContext, Looper.myLooper());
+        verify(mSensorManager, atLeastOnce()).registerListener(mLightSensorListenerCaptor.capture(),
+                        eq(mLightSensor), anyInt(), any());
+        mLightSensorListenerCaptor.getValue().onSensorChanged(new SensorEvent(mLightSensor, 0,
+                TimeUnit.MILLISECONDS.toNanos(timestamp), new float[] {value}));
     }
 
     private Light getNextLight(boolean cameraType) {
@@ -427,10 +363,6 @@
         return light;
     }
 
-    private float getLightSensorValue(int i) {
-        return (float) Math.exp(i / CameraPrivacyLightController.LIGHT_VALUE_MULTIPLIER);
-    }
-
     private void openCamera() {
         verify(mAppOpsManager).startWatchingActive(any(), any(), mAppOpsListenerCaptor.capture());
         mAppOpsListenerCaptor.getValue().onOpActiveChanged(OPSTR_CAMERA, 10001, "pkg", true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
new file mode 100644
index 0000000..3514276
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SLEEP_ON_FOLD;
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_STAY_AWAKE_ON_FOLD;
+
+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.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class FoldSettingProviderTest {
+
+    private static final String SETTING_VALUE_INVALID = "invalid_fold_lock_behavior";
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private SettingsWrapper mSettingsWrapper;
+    private ContentResolver mContentResolver;
+    private FoldSettingProvider mFoldSettingProvider;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContentResolver =
+                InstrumentationRegistry.getInstrumentation().getContext().getContentResolver();
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mResources);
+        setFoldLockBehaviorAvailability(true);
+
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+    }
+
+    @Test
+    public void foldSettingNotAvailable_returnDefaultSetting() {
+        setFoldLockBehaviorAvailability(false);
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+        boolean shouldSelectiveStayAwakeOnFold =
+                mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+        assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+    }
+
+    @Test
+    public void foldSettingNotAvailable_notReturnStayAwakeOnFoldTrue() {
+        setFoldLockBehaviorAvailability(false);
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+        boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+        assertThat(shouldStayAwakeOnFold).isFalse();
+    }
+
+    @Test
+    public void foldSettingNotAvailable_notReturnSleepOnFoldTrue() {
+        setFoldLockBehaviorAvailability(false);
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_SLEEP_ON_FOLD);
+        mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+        boolean shouldSleepOnFold = mFoldSettingProvider.shouldSleepOnFold();
+
+        assertThat(shouldSleepOnFold).isFalse();
+    }
+
+    @Test
+    public void foldSettingAvailable_returnCorrectFoldSetting() {
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+
+        boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+        assertThat(shouldStayAwakeOnFold).isTrue();
+    }
+
+    @Test
+    public void foldSettingInvalid_returnDefaultSetting() {
+        setFoldLockBehaviorSettingValue(SETTING_VALUE_INVALID);
+
+        boolean shouldSelectiveStayAwakeOnFold =
+                mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+        assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+    }
+
+    @Test
+    public void foldSettingNotDefined_returnDefaultSetting() {
+        setFoldLockBehaviorSettingValue(null);
+
+        boolean shouldSelectiveStayAwakeOnFold =
+                mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+        assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+    }
+
+    private void setFoldLockBehaviorAvailability(boolean isFoldLockBehaviorEnabled) {
+        when(mResources.getBoolean(R.bool.config_fold_lock_behavior)).thenReturn(
+                isFoldLockBehaviorEnabled);
+    }
+
+    private void setFoldLockBehaviorSettingValue(String foldLockBehaviorSettingValue) {
+        when(mSettingsWrapper.getStringForUser(any(),
+                eq(Settings.System.FOLD_LOCK_BEHAVIOR),
+                eq(UserHandle.USER_CURRENT))).thenReturn(foldLockBehaviorSettingValue);
+    }
+}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 534aa89..93cbea6 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -243,8 +243,10 @@
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;
         final boolean includeProcessStateData = (query.getFlags()
                 & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0;
+        final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold();
         BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(
-                customPowerComponentNames, includePowerModels, includeProcessStateData);
+                customPowerComponentNames, includePowerModels, includeProcessStateData,
+                minConsumedPowerThreshold);
         SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats();
         for (int i = 0; i < uidStats.size(); i++) {
             builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i));
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
index 266a226..07c486c 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsTest.java
@@ -181,7 +181,7 @@
         final BatteryUsageStats stats2 = buildBatteryUsageStats2(new String[]{"FOO"}, true).build();
 
         final BatteryUsageStats sum =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true)
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, 0)
                         .add(stats1)
                         .add(stats2)
                         .build();
@@ -222,7 +222,7 @@
     @Test
     public void testAdd_customComponentMismatch() {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true);
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, 0);
         final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"BAR"}, false).build();
 
         assertThrows(IllegalArgumentException.class, () -> builder.add(stats));
@@ -231,7 +231,7 @@
     @Test
     public void testAdd_processStateDataMismatch() {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true);
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, 0);
         final BatteryUsageStats stats = buildBatteryUsageStats2(new String[]{"FOO"}, false).build();
 
         assertThrows(IllegalArgumentException.class, () -> builder.add(stats));
@@ -260,7 +260,7 @@
         final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
 
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true)
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, true, 0)
                         .setBatteryCapacity(4000)
                         .setDischargePercentage(20)
                         .setDischargedPowerRange(1000, 2000)
@@ -305,7 +305,7 @@
 
         final BatteryUsageStats.Builder builder =
                 new BatteryUsageStats.Builder(customPowerComponentNames, true,
-                        includeProcessStateData);
+                        includeProcessStateData, 0);
         builder.setDischargePercentage(30)
                 .setDischargedPowerRange(1234, 2345)
                 .setStatsStartTimestamp(2000)
diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies_keep_profiles_running_false.xml b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies_keep_profiles_running_false.xml
new file mode 100644
index 0000000..4785a88
--- /dev/null
+++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies_keep_profiles_running_false.xml
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true" provisioning-state="3">
+    <keep-profiles-running value="false" />
+    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
+        <policies flags="991" />
+        <strong-auth-unlock-timeout value="0" />
+        <organization-color value="-16738680" />
+        <active-password value="0" />
+    </admin>
+</policies>
diff --git a/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies_keep_profiles_running_true.xml b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies_keep_profiles_running_true.xml
new file mode 100644
index 0000000..07ec229
--- /dev/null
+++ b/services/tests/servicestests/assets/PolicyVersionUpgraderTest/device_policies_keep_profiles_running_true.xml
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true" provisioning-state="3">
+    <keep-profiles-running value="true" />
+    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
+        <policies flags="991" />
+        <strong-auth-unlock-timeout value="0" />
+        <organization-color value="-16738680" />
+        <active-password value="0" />
+    </admin>
+</policies>
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index b79c7be..349a597 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -303,6 +303,7 @@
         });
     }
 
+    @FlakyTest(bugId = 297879316)
     @Test
     public void testStates_areMutuallyExclusive() {
         forEachState(state1 -> {
@@ -523,6 +524,7 @@
         });
     }
 
+    @FlakyTest(bugId = 297879316)
     @Test
     public void testTwoFingersOneTap_activatedState_dispatchMotionEvents() {
         goFromStateIdleTo(STATE_ACTIVATED);
@@ -583,6 +585,7 @@
         returnToNormalFrom(STATE_ACTIVATED);
     }
 
+    @FlakyTest(bugId = 297879316)
     @Test
     public void testFirstFingerSwipe_twoPointerDownAndActivatedState_panningState() {
         goFromStateIdleTo(STATE_ACTIVATED);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index bbbab21..a0bca3b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -50,6 +50,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.platform.test.annotations.FlakyTest;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.view.InputDevice;
@@ -307,6 +308,7 @@
                 MagnificationScaleProvider.MAX_SCALE);
     }
 
+    @FlakyTest(bugId = 297879435)
     @Test
     public void logTrackingTypingFocus_processScroll_logDuration() {
         WindowMagnificationManager spyWindowMagnificationManager = spy(mWindowMagnificationManager);
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index aba24fb..7f8ad45 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -261,7 +261,8 @@
         // Verify disconnection has been cancelled and we're seeing two connections attempts,
         // with the device connected at the end of the test
         verify(mSpyDevInventory, times(2)).onSetBtActiveDevice(
-                any(AudioDeviceBroker.BtDeviceInfo.class), anyInt());
+                any(AudioDeviceBroker.BtDeviceInfo.class), anyInt() /*codec*/,
+                anyInt() /*streamType*/);
         Assert.assertTrue("Mock device not connected",
                 mSpyDevInventory.isA2dpDeviceConnected(mFakeBtDevice));
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
index 64e776e..0b730f1 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
@@ -21,6 +21,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -78,6 +79,8 @@
     @Mock
     private SharedPreferences mSharedPreferences;
     @Mock
+    private SharedPreferences.Editor mEditor;
+    @Mock
     private BiometricNotification mBiometricNotification;
 
     @Before
@@ -99,6 +102,8 @@
         when(mContext.getSharedPreferences(any(File.class), anyInt()))
                 .thenReturn(mSharedPreferences);
         when(mSharedPreferences.getStringSet(anyString(), anySet())).thenReturn(emptySet());
+        when(mSharedPreferences.edit()).thenReturn(mEditor);
+        when(mEditor.putFloat(anyString(), anyFloat())).thenReturn(mEditor);
 
         mAuthenticationStatsCollector = new AuthenticationStatsCollector(mContext,
                 0 /* modality */, mBiometricNotification);
@@ -181,6 +186,7 @@
                 .getAuthenticationStatsForUser(USER_ID_1);
         assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+        assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
         assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
     }
 
@@ -203,6 +209,8 @@
                 .getAuthenticationStatsForUser(USER_ID_1);
         assertThat(authenticationStats.getTotalAttempts()).isEqualTo(500);
         assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(400);
+        assertThat(authenticationStats.getEnrollmentNotifications())
+                .isEqualTo(MAXIMUM_ENROLLMENT_NOTIFICATIONS);
         assertThat(authenticationStats.getFrr()).isWithin(0f).of(0.8f);
     }
 
@@ -230,6 +238,7 @@
                 .getAuthenticationStatsForUser(USER_ID_1);
         assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+        assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
         assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
     }
 
@@ -256,6 +265,7 @@
                 .getAuthenticationStatsForUser(USER_ID_1);
         assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
+        assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(0);
         assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
     }
 
@@ -284,6 +294,8 @@
         assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+        // Assert that notification count has been updated.
+        assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(1);
     }
 
     @Test
@@ -311,5 +323,7 @@
         assertThat(authenticationStats.getTotalAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getRejectedAttempts()).isEqualTo(0);
         assertThat(authenticationStats.getFrr()).isWithin(0f).of(-1.0f);
+        // Assert that notification count has been updated.
+        assertThat(authenticationStats.getEnrollmentNotifications()).isEqualTo(1);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java
index dde2a3c..32c55eb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsPersisterTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anySet;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -63,6 +64,8 @@
     private static final String FINGERPRINT_REJECTIONS = "fingerprint_rejections";
     private static final String ENROLLMENT_NOTIFICATIONS = "enrollment_notifications";
     private static final String KEY = "frr_stats";
+    private static final String THRESHOLD_KEY = "frr_threshold";
+    private static final float FRR_THRESHOLD = 0.25f;
 
     @Mock
     private Context mContext;
@@ -74,6 +77,8 @@
 
     @Captor
     private ArgumentCaptor<Set<String>> mStringSetArgumentCaptor;
+    @Captor
+    private ArgumentCaptor<Float> mFrrThresholdArgumentCaptor;
 
     @Before
     public void setUp() {
@@ -81,6 +86,7 @@
                 .thenReturn(mSharedPreferences);
         when(mSharedPreferences.edit()).thenReturn(mEditor);
         when(mEditor.putStringSet(anyString(), anySet())).thenReturn(mEditor);
+        when(mEditor.putFloat(anyString(), anyFloat())).thenReturn(mEditor);
 
         mAuthenticationStatsPersister = new AuthenticationStatsPersister(mContext);
     }
@@ -217,6 +223,31 @@
     }
 
     @Test
+    public void persistFrrStats_multiUser_newUser_shouldUpdateRecord() throws JSONException {
+        AuthenticationStats authenticationStats1 = new AuthenticationStats(USER_ID_1,
+                300 /* totalAttempts */, 10 /* rejectedAttempts */,
+                0 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FACE);
+        AuthenticationStats authenticationStats2 = new AuthenticationStats(USER_ID_2,
+                100 /* totalAttempts */, 5 /* rejectedAttempts */,
+                1 /* enrollmentNotifications */, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+
+        // Sets up the shared preference with user 1 only.
+        when(mSharedPreferences.getStringSet(eq(KEY), anySet())).thenReturn(
+                Set.of(buildFrrStats(authenticationStats1)));
+
+        // Add data for user 2.
+        mAuthenticationStatsPersister.persistFrrStats(authenticationStats2.getUserId(),
+                authenticationStats2.getTotalAttempts(),
+                authenticationStats2.getRejectedAttempts(),
+                authenticationStats2.getEnrollmentNotifications(),
+                authenticationStats2.getModality());
+
+        verify(mEditor).putStringSet(eq(KEY), mStringSetArgumentCaptor.capture());
+        assertThat(mStringSetArgumentCaptor.getValue())
+                .contains(buildFrrStats(authenticationStats2));
+    }
+
+    @Test
     public void removeFrrStats_existingUser_shouldUpdateRecord() throws JSONException {
         AuthenticationStats authenticationStats = new AuthenticationStats(USER_ID_1,
                 300 /* totalAttempts */, 10 /* rejectedAttempts */,
@@ -230,6 +261,14 @@
         assertThat(mStringSetArgumentCaptor.getValue()).doesNotContain(authenticationStats);
     }
 
+    @Test
+    public void persistFrrThreshold_shouldUpdateRecord() {
+        mAuthenticationStatsPersister.persistFrrThreshold(FRR_THRESHOLD);
+
+        verify(mEditor).putFloat(eq(THRESHOLD_KEY), mFrrThresholdArgumentCaptor.capture());
+        assertThat(mFrrThresholdArgumentCaptor.getValue()).isWithin(0f).of(FRR_THRESHOLD);
+    }
+
     private String buildFrrStats(AuthenticationStats authenticationStats)
             throws JSONException {
         if (authenticationStats.getModality() == BiometricsProtoEnums.MODALITY_FACE) {
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 00e35ec..41af9e3 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
@@ -129,7 +129,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -296,19 +295,20 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices= */ true,
                 targetDisplayCategory);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
         return blockedAppIntent;
     }
 
 
-    private ArrayList<ActivityInfo> getActivityInfoList(
+    private ActivityInfo getActivityInfo(
             String packageName, String name, boolean displayOnRemoveDevices,
             String requiredDisplayCategory) {
         ActivityInfo activityInfo = new ActivityInfo();
@@ -318,7 +318,7 @@
                 ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
         activityInfo.applicationInfo = mApplicationInfoMock;
         activityInfo.requiredDisplayCategory = requiredDisplayCategory;
-        return new ArrayList<>(Arrays.asList(activityInfo));
+        return activityInfo;
     }
 
     @Before
@@ -1414,14 +1414,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext, never()).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1434,14 +1435,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
                 /* displayOnRemoveDevices */  false,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1454,14 +1456,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 SETTINGS_PACKAGE_NAME,
                 SETTINGS_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1474,14 +1477,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 VENDING_PACKAGE_NAME,
                 VENDING_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1494,14 +1498,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 GOOGLE_DIALER_PACKAGE_NAME,
                 GOOGLE_DIALER_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1514,14 +1519,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 GOOGLE_MAPS_PACKAGE_NAME,
                 GOOGLE_MAPS_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1561,12 +1567,12 @@
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isTrue();
     }
@@ -1585,7 +1591,7 @@
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
@@ -1597,7 +1603,7 @@
 
         // register interceptor and intercept intent
         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isFalse();
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -1609,7 +1615,7 @@
 
         // unregister interceptor and launch activity
         mDeviceImpl.unregisterIntentInterceptor(interceptor);
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isTrue();
     }
@@ -1628,7 +1634,7 @@
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
@@ -1640,7 +1646,7 @@
         // register interceptor with different filter
         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
 
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isTrue();
     }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index 28df24c..c65452a 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -16,21 +16,31 @@
 
 package com.android.server.companion.virtual;
 
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
 import static android.content.Context.DEVICE_ID_DEFAULT;
 import static android.content.Context.DEVICE_ID_INVALID;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.when;
 
+import android.companion.virtual.IVirtualDevice;
 import android.companion.virtual.VirtualDevice;
+import android.companion.virtual.flags.Flags;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -40,24 +50,35 @@
     private static final String PERSISTENT_ID = "persistentId";
     private static final String DEVICE_NAME = "VirtualDeviceName";
 
+    @Mock
+    private IVirtualDevice mVirtualDevice;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
     @Test
     public void build_invalidId_shouldThrowIllegalArgumentException() {
         assertThrows(
                 IllegalArgumentException.class,
-                () -> new VirtualDevice(DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
+                () -> new VirtualDevice(
+                        mVirtualDevice, DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
     }
 
     @Test
     public void build_defaultId_shouldThrowIllegalArgumentException() {
         assertThrows(
                 IllegalArgumentException.class,
-                () -> new VirtualDevice(DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
+                () -> new VirtualDevice(
+                        mVirtualDevice, DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
     }
 
     @Test
     public void build_onlyRequiredFields() {
         VirtualDevice virtualDevice =
-                new VirtualDevice(VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+                new VirtualDevice(
+                        mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
         assertThat(virtualDevice.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
         assertThat(virtualDevice.getPersistentDeviceId()).isNull();
         assertThat(virtualDevice.getName()).isNull();
@@ -66,15 +87,43 @@
     @Test
     public void parcelable_shouldRecreateSuccessfully() {
         VirtualDevice originalDevice =
-                new VirtualDevice(VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
+                new VirtualDevice(mVirtualDevice, VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
         Parcel parcel = Parcel.obtain();
         originalDevice.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
 
         VirtualDevice device = VirtualDevice.CREATOR.createFromParcel(parcel);
-        assertThat(device).isEqualTo(originalDevice);
         assertThat(device.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
         assertThat(device.getPersistentDeviceId()).isEqualTo(PERSISTENT_ID);
         assertThat(device.getName()).isEqualTo(DEVICE_NAME);
     }
+
+    @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
+    @Test
+    public void virtualDevice_getDisplayIds() throws Exception {
+        VirtualDevice virtualDevice =
+                new VirtualDevice(
+                        mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+
+        when(mVirtualDevice.getDisplayIds()).thenReturn(new int[0]);
+        assertThat(virtualDevice.getDisplayIds()).hasLength(0);
+
+        final int[] displayIds = new int[]{7, 18};
+        when(mVirtualDevice.getDisplayIds()).thenReturn(displayIds);
+        assertThat(virtualDevice.getDisplayIds()).isEqualTo(displayIds);
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
+    @Test
+    public void virtualDevice_hasCustomSensorSupport() throws Exception {
+        VirtualDevice virtualDevice =
+                new VirtualDevice(
+                        mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+
+        when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS)).thenReturn(DEVICE_POLICY_DEFAULT);
+        assertThat(virtualDevice.hasCustomSensorSupport()).isFalse();
+
+        when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS)).thenReturn(DEVICE_POLICY_CUSTOM);
+        assertThat(virtualDevice.hasCustomSensorSupport()).isTrue();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 2bfa44e..78655a5 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -25,7 +25,6 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
 import android.content.Context;
@@ -79,11 +78,10 @@
                         FLAG_SECURE,
                         SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
                         /* allowedUsers= */ new ArraySet<>(),
-                        /* allowedCrossTaskNavigations= */ new ArraySet<>(),
-                        /* blockedCrossTaskNavigations= */ new ArraySet<>(),
-                        /* allowedActivities= */ new ArraySet<>(),
-                        /* blockedActivities= */ new ArraySet<>(),
-                        VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
+                        /* activityLaunchAllowedByDefault= */ true,
+                        /* activityPolicyExceptions= */ new ArraySet<>(),
+                        /* crossTaskNavigationAllowedByDefault= */ true,
+                        /* crossTaskNavigationExceptions= */ new ArraySet<>(),
                         /* activityListener= */ null,
                         /* pipBlockedCallback= */ null,
                         /* activityBlockedCallback= */ null,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f408ef0..f4dac2c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1144,6 +1144,10 @@
                 eq(UserManager.DISALLOW_ADD_CLONE_PROFILE),
                 eq(true), eq(UserHandle.SYSTEM));
 
+        verify(getServices().userManager, times(1)).setUserRestriction(
+                eq(UserManager.DISALLOW_ADD_PRIVATE_PROFILE),
+                eq(true), eq(UserHandle.SYSTEM));
+
         verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -1422,6 +1426,10 @@
                 .setUserRestriction(eq(UserManager.DISALLOW_ADD_CLONE_PROFILE), eq(false),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
+        verify(getServices().userManager)
+                .setUserRestriction(eq(UserManager.DISALLOW_ADD_PRIVATE_PROFILE), eq(false),
+                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
index eb2ee35..d2b921d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/PolicyVersionUpgraderTest.java
@@ -76,7 +76,7 @@
 public class PolicyVersionUpgraderTest extends DpmTestBase {
     // NOTE: Only change this value if the corresponding CL also adds a test to test the upgrade
     // to the new version.
-    private static final int LATEST_TESTED_VERSION = 5;
+    private static final int LATEST_TESTED_VERSION = 6;
     public static final String PERMISSIONS_TAG = "admin-can-grant-sensors-permissions";
     public static final String DEVICE_OWNER_XML = "device_owner_2.xml";
     private ComponentName mFakeAdmin;
@@ -313,7 +313,7 @@
     }
 
     @Test
-    public void testEffectiveKeepProfilesRunningSet() throws Exception {
+    public void testEffectiveKeepProfilesRunningSetToFalse4To5() throws Exception {
         writeVersionToXml(4);
 
         final int userId = UserHandle.USER_SYSTEM;
@@ -327,8 +327,109 @@
         Document policies = readPolicies(userId);
         Element keepProfilesRunning = (Element) policies.getDocumentElement()
                 .getElementsByTagName("keep-profiles-running").item(0);
-        assertThat(keepProfilesRunning.getAttribute("value")).isEqualTo("false");
+
+        // Default value (false) is not serialized.
+        assertThat(keepProfilesRunning).isNull();
     }
+    @Test
+    public void testEffectiveKeepProfilesRunningIsToFalse4To6() throws Exception {
+        writeVersionToXml(4);
+
+        final int userId = UserHandle.USER_SYSTEM;
+        mProvider.mUsers = new int[]{userId};
+        preparePoliciesFile(userId, "device_policies.xml");
+
+        mUpgrader.upgradePolicy(6);
+
+        assertThat(readVersionFromXml()).isAtLeast(6);
+
+        Document policies = readPolicies(userId);
+        Element keepProfilesRunning = (Element) policies.getDocumentElement()
+                .getElementsByTagName("keep-profiles-running").item(0);
+
+        // Default value (false) is not serialized.
+        assertThat(keepProfilesRunning).isNull();
+    }
+
+    /**
+     * Verify correct behaviour when upgrading from Android 13
+     */
+    @Test
+    public void testEffectiveKeepProfilesRunningIsToFalse3To6() throws Exception {
+        writeVersionToXml(3);
+
+        final int userId = UserHandle.USER_SYSTEM;
+        mProvider.mUsers = new int[]{userId};
+        preparePoliciesFile(userId, "device_policies.xml");
+
+        mUpgrader.upgradePolicy(6);
+
+        assertThat(readVersionFromXml()).isAtLeast(6);
+
+        Document policies = readPolicies(userId);
+        Element keepProfilesRunning = (Element) policies.getDocumentElement()
+                .getElementsByTagName("keep-profiles-running").item(0);
+
+        // Default value (false) is not serialized.
+        assertThat(keepProfilesRunning).isNull();
+    }
+
+    @Test
+    public void testEffectiveKeepProfilesRunningMissingInV5() throws Exception {
+        writeVersionToXml(5);
+
+        final int userId = UserHandle.USER_SYSTEM;
+        mProvider.mUsers = new int[]{userId};
+        preparePoliciesFile(userId, "device_policies.xml");
+
+        mUpgrader.upgradePolicy(6);
+
+        assertThat(readVersionFromXml()).isAtLeast(6);
+
+        Document policies = readPolicies(userId);
+        Element keepProfilesRunning = (Element) policies.getDocumentElement()
+                .getElementsByTagName("keep-profiles-running").item(0);
+        assertThat(keepProfilesRunning.getAttribute("value")).isEqualTo("true");
+    }
+
+    @Test
+    public void testEffectiveKeepProfilesRunningTrueInV5() throws Exception {
+        writeVersionToXml(5);
+
+        final int userId = UserHandle.USER_SYSTEM;
+        mProvider.mUsers = new int[]{userId};
+        preparePoliciesFile(userId, "device_policies_keep_profiles_running_true.xml");
+
+        mUpgrader.upgradePolicy(6);
+
+        assertThat(readVersionFromXml()).isAtLeast(6);
+
+        Document policies = readPolicies(userId);
+        Element keepProfilesRunning = (Element) policies.getDocumentElement()
+                .getElementsByTagName("keep-profiles-running").item(0);
+        assertThat(keepProfilesRunning.getAttribute("value")).isEqualTo("true");
+    }
+
+    @Test
+    public void testEffectiveKeepProfilesRunningFalseInV5() throws Exception {
+        writeVersionToXml(5);
+
+        final int userId = UserHandle.USER_SYSTEM;
+        mProvider.mUsers = new int[]{userId};
+        preparePoliciesFile(userId, "device_policies_keep_profiles_running_false.xml");
+
+        mUpgrader.upgradePolicy(6);
+
+        assertThat(readVersionFromXml()).isAtLeast(6);
+
+        Document policies = readPolicies(userId);
+        Element keepProfilesRunning = (Element) policies.getDocumentElement()
+                .getElementsByTagName("keep-profiles-running").item(0);
+
+        // Default value (false) is not serialized.
+        assertThat(keepProfilesRunning).isNull();
+    }
+
 
     @Test
     public void isLatestVersionTested() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index ecd35a5..b22798e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1174,6 +1174,24 @@
         }
     }
 
+    // Make sure the creation of a private profile fails if DISALLOW_ADD_PRIVATE_PROFILE is true.
+    @MediumTest
+    @Test
+    public void testCreateProfileForUser_disallowAddPrivateProfile() {
+        final int mainUserId = ActivityManager.getCurrentUser();
+        final UserHandle mainUserHandle = asHandle(mainUserId);
+        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                true, mainUserHandle);
+        try {
+            UserInfo privateProfileInfo = createProfileForUser("Private",
+                    UserManager.USER_TYPE_PROFILE_PRIVATE, mainUserId);
+            assertThat(privateProfileInfo).isNull();
+        } finally {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, false,
+                    mainUserHandle);
+        }
+    }
+
     @MediumTest
     @Test
     public void testAddRestrictedProfile() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index a387d4a..9907bd6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -72,6 +72,8 @@
     public void testCanDeviceOwnerChange() {
         assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_RECORD_AUDIO));
         assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_WALLPAPER));
+        assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(
+                UserManager.DISALLOW_ADD_PRIVATE_PROFILE));
         assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_ADD_USER));
         assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_USER_SWITCH));
     }
@@ -83,6 +85,8 @@
                 UserManager.DISALLOW_WALLPAPER, true));
         assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
                 UserManager.DISALLOW_USER_SWITCH, true));
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_ADD_PRIVATE_PROFILE, true));
         assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
                 UserManager.DISALLOW_ADD_USER, true));
         assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 4b65895..2dacda0 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -34,6 +34,7 @@
         "platform-test-annotations",
         "platformprotosnano",
         "statsdprotolite",
+        "StatsdTestUtils",
         "hamcrest-library",
         "servicestests-utils",
         "testables",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 37f4983..70e5c2e1 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -83,7 +83,6 @@
 
 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.FSI_FORCE_DEMOTE;
 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI;
-import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.WAKE_LOCK_FOR_POSTING_NOTIFICATION;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
@@ -128,7 +127,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import static java.util.Collections.emptyList;
@@ -596,9 +594,6 @@
                     mAcquiredWakeLocks.add(wl);
                     return wl;
                 });
-        mTestFlagResolver.setFlagOverride(WAKE_LOCK_FOR_POSTING_NOTIFICATION, true);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, "true", false);
 
         // apps allowed as convos
         mService.setStringArrayResourceValue(PKG_O);
@@ -1964,34 +1959,6 @@
     }
 
     @Test
-    public void enqueueNotification_wakeLockSystemPropertyOff_noWakeLock() throws Exception {
-        mTestFlagResolver.setFlagOverride(WAKE_LOCK_FOR_POSTING_NOTIFICATION, false);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, "true", false);
-
-        mBinderService.enqueueNotificationWithTag(PKG, PKG,
-                "enqueueNotification_setsWakeLockWorkSource", 0,
-                generateNotificationRecord(null).getNotification(), 0);
-        waitForIdle();
-
-        verifyZeroInteractions(mPowerManager);
-    }
-
-    @Test
-    public void enqueueNotification_wakeLockDeviceConfigOff_noWakeLock() throws Exception {
-        mTestFlagResolver.setFlagOverride(WAKE_LOCK_FOR_POSTING_NOTIFICATION, true);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
-                SystemUiDeviceConfigFlags.NOTIFY_WAKELOCK, "false", false);
-
-        mBinderService.enqueueNotificationWithTag(PKG, PKG,
-                "enqueueNotification_setsWakeLockWorkSource", 0,
-                generateNotificationRecord(null).getNotification(), 0);
-        waitForIdle();
-
-        verifyZeroInteractions(mPowerManager);
-    }
-
-    @Test
     public void testCancelNonexistentNotification() throws Exception {
         mBinderService.cancelNotificationWithTag(PKG, PKG,
                 "testCancelNonexistentNotification", 0, 0);
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 9b745f5..020afdb 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -44,22 +44,11 @@
 import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION;
 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
 import static android.os.UserHandle.USER_SYSTEM;
-import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS;
-import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
-import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IMPORTANCE_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_CONVERSATION_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DELETED_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DEMOTED_CONVERSATION_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_IMPORTANT_CONVERSATION_FIELD_NUMBER;
-import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.UID_FIELD_NUMBER;
 import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER;
 import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
@@ -134,6 +123,7 @@
 import android.util.IntArray;
 import android.util.Pair;
 import android.util.StatsEvent;
+import android.util.StatsEventTestUtils;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 
@@ -144,11 +134,14 @@
 import com.android.internal.config.sysui.TestableFlagResolver;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
+import com.android.os.AtomsProto;
+import com.android.os.AtomsProto.PackageNotificationChannelPreferences;
 import com.android.os.AtomsProto.PackageNotificationPreferences;
 import com.android.server.UiServiceTestCase;
 import com.android.server.notification.PermissionHelper.PackagePermission;
 
 import com.google.common.collect.ImmutableList;
+import com.google.protobuf.InvalidProtocolBufferException;
 
 import org.json.JSONArray;
 import org.json.JSONObject;
@@ -218,7 +211,6 @@
     private PreferencesHelper mHelper;
     private AudioAttributes mAudioAttributes;
     private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
-    private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
 
     @Before
     public void setUp() throws Exception {
@@ -331,11 +323,9 @@
 
         when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0}));
 
-        mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
-
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mStatsEventBuilderFactory, false);
+                false);
         resetZenModeHelper();
 
         mAudioAttributes = new AudioAttributes.Builder()
@@ -683,7 +673,7 @@
     public void testReadXml_oldXml_migrates() throws Exception {
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ true);
+                /* showReviewPermissionsNotification= */ true);
 
         String xml = "<ranking version=\"2\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1
@@ -825,7 +815,7 @@
     public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ true);
+                /* showReviewPermissionsNotification= */ true);
 
         String xml = "<ranking version=\"3\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -883,7 +873,7 @@
     public void testReadXml_newXml_permissionNotificationOff() throws Exception {
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ false);
+                /* showReviewPermissionsNotification= */ false);
 
         String xml = "<ranking version=\"3\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -941,7 +931,7 @@
     public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mStatsEventBuilderFactory, /* showReviewPermissionsNotification= */ true);
+                /* showReviewPermissionsNotification= */ true);
 
         String xml = "<ranking version=\"4\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -1521,7 +1511,7 @@
 
         mHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mStatsEventBuilderFactory, false);
+                false);
 
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -5392,7 +5382,7 @@
     }
 
     @Test
-    public void testPullPackageChannelPreferencesStats() {
+    public void testPullPackageChannelPreferencesStats() throws InvalidProtocolBufferException {
         String channelId = "parent";
         String name = "messages";
         NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
@@ -5406,25 +5396,40 @@
         ArrayList<StatsEvent> events = new ArrayList<>();
         mHelper.pullPackageChannelPreferencesStats(events);
 
-        int found = 0;
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
-                    && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
-                ++found;
-                assertEquals("uid", UID_O, builder.getValue(UID_FIELD_NUMBER));
-                assertTrue("uid annotation", builder.getBooleanAnnotation(
-                        UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID));
-                assertEquals("importance", IMPORTANCE_DEFAULT, builder.getValue(
-                        IMPORTANCE_FIELD_NUMBER));
-                assertEquals("name", name, builder.getValue(CHANNEL_NAME_FIELD_NUMBER));
-                assertFalse("isconv", builder.getBoolean(IS_CONVERSATION_FIELD_NUMBER));
-                assertFalse("deleted", builder.getBoolean(IS_DELETED_FIELD_NUMBER));
+        // number of channels with preferences should be 3 total
+        assertEquals("expected number of events", 3, events.size());
+        for (StatsEvent ev : events) {
+            // all of these events should be of PackageNotificationChannelPreferences type,
+            // and therefore we expect the atom to have this field.
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasPackageNotificationChannelPreferences());
+            PackageNotificationChannelPreferences p =
+                    atom.getPackageNotificationChannelPreferences();
+
+            // uid is shared across all channels; conversation & deleted are not set in any of
+            // these channels; beyond that check individual channel properties
+            assertEquals("uid", UID_O, p.getUid());
+            assertFalse("is conversation", p.getIsConversation());
+            assertFalse("is deleted", p.getIsDeleted());
+
+            String eventChannelId = p.getChannelId();
+            if (eventChannelId.equals(channelId)) {
+                assertEquals("channel name", name, p.getChannelName());
+                assertEquals("importance", IMPORTANCE_DEFAULT, p.getImportance());
+                assertFalse("is conversation", p.getIsConversation());
+            } else if (eventChannelId.equals("a")) {
+                assertEquals("channel name", "a", p.getChannelName());
+                assertEquals("importance", IMPORTANCE_LOW, p.getImportance());
+            } else { // b
+                assertEquals("channel name", "b", p.getChannelName());
+                assertEquals("importance", IMPORTANCE_HIGH, p.getImportance());
             }
         }
     }
 
     @Test
-    public void testPullPackageChannelPreferencesStats_one_to_one() {
+    public void testPullPackageChannelPreferencesStats_one_to_one()
+            throws InvalidProtocolBufferException {
         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
         mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false);
         NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW);
@@ -5437,19 +5442,22 @@
         ArrayList<StatsEvent> events = new ArrayList<>();
         mHelper.pullPackageChannelPreferencesStats(events);
 
-        int found = 0;
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES) {
-                Object id = builder.getValue(CHANNEL_ID_FIELD_NUMBER);
-                assertTrue("missing channel in the output", channels.contains(id));
-                channels.remove(id);
-            }
+        assertEquals("total events", 3, events.size());
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasPackageNotificationChannelPreferences());
+            PackageNotificationChannelPreferences p =
+                    atom.getPackageNotificationChannelPreferences();
+            String id = p.getChannelId();
+            assertTrue("missing channel in the output", channels.contains(id));
+            channels.remove(id);
         }
         assertTrue("unexpected channel in output", channels.isEmpty());
     }
 
     @Test
-    public void testPullPackageChannelPreferencesStats_conversation() {
+    public void testPullPackageChannelPreferencesStats_conversation()
+            throws InvalidProtocolBufferException {
         String conversationId = "friend";
 
         NotificationChannel parent =
@@ -5467,21 +5475,25 @@
         ArrayList<StatsEvent> events = new ArrayList<>();
         mHelper.pullPackageChannelPreferencesStats(events);
 
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
-                    && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
-                assertTrue("isConveration should be true", builder.getBoolean(
-                        IS_CONVERSATION_FIELD_NUMBER));
-                assertFalse("not demoted", builder.getBoolean(
-                        IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
-                assertFalse("not important", builder.getBoolean(
-                        IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
+        // In this case, we want to check the properties of the conversation channel (not parent)
+        assertEquals("total events", 2, events.size());
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasPackageNotificationChannelPreferences());
+            PackageNotificationChannelPreferences p =
+                    atom.getPackageNotificationChannelPreferences();
+
+            if (channelId.equals(p.getChannelId())) {
+                assertTrue("isConversation should be true", p.getIsConversation());
+                assertFalse("not demoted", p.getIsDemotedConversation());
+                assertFalse("not important", p.getIsImportantConversation());
             }
         }
     }
 
     @Test
-    public void testPullPackageChannelPreferencesStats_conversation_demoted() {
+    public void testPullPackageChannelPreferencesStats_conversation_demoted()
+            throws InvalidProtocolBufferException {
         NotificationChannel parent =
                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
@@ -5496,21 +5508,23 @@
         ArrayList<StatsEvent> events = new ArrayList<>();
         mHelper.pullPackageChannelPreferencesStats(events);
 
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
-                    && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
-                assertTrue("isConveration should be true", builder.getBoolean(
-                        IS_CONVERSATION_FIELD_NUMBER));
-                assertTrue("is demoted", builder.getBoolean(
-                        IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
-                assertFalse("not important", builder.getBoolean(
-                        IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
+        assertEquals("total events", 2, events.size());
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasPackageNotificationChannelPreferences());
+            PackageNotificationChannelPreferences p =
+                    atom.getPackageNotificationChannelPreferences();
+            if (channelId.equals(p.getChannelId())) {
+                assertTrue("isConversation should be true", p.getIsConversation());
+                assertTrue("is demoted", p.getIsDemotedConversation());
+                assertFalse("not important", p.getIsImportantConversation());
             }
         }
     }
 
     @Test
-    public void testPullPackageChannelPreferencesStats_conversation_priority() {
+    public void testPullPackageChannelPreferencesStats_conversation_priority()
+            throws InvalidProtocolBufferException {
         NotificationChannel parent =
                 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
         mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false);
@@ -5525,21 +5539,23 @@
         ArrayList<StatsEvent> events = new ArrayList<>();
         mHelper.pullPackageChannelPreferencesStats(events);
 
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
-                    && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
-                assertTrue("isConveration should be true", builder.getBoolean(
-                        IS_CONVERSATION_FIELD_NUMBER));
-                assertFalse("not demoted", builder.getBoolean(
-                        IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
-                assertTrue("is important", builder.getBoolean(
-                        IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
+        assertEquals("total events", 2, events.size());
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasPackageNotificationChannelPreferences());
+            PackageNotificationChannelPreferences p =
+                    atom.getPackageNotificationChannelPreferences();
+            if (channelId.equals(p.getChannelId())) {
+                assertTrue("isConversation should be true", p.getIsConversation());
+                assertFalse("not demoted", p.getIsDemotedConversation());
+                assertTrue("is important", p.getIsImportantConversation());
             }
         }
     }
 
     @Test
-    public void testPullPackagePreferencesStats_postPermissionMigration() {
+    public void testPullPackagePreferencesStats_postPermissionMigration()
+            throws InvalidProtocolBufferException {
         // make sure there's at least one channel for each package we want to test
         NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false,
@@ -5568,23 +5584,18 @@
         ArrayList<StatsEvent> events = new ArrayList<>();
         mHelper.pullPackagePreferencesStats(events, appPermissions);
 
-        int found = 0;
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == PACKAGE_NOTIFICATION_PREFERENCES) {
-                ++found;
-                int uid = builder.getInt(PackageNotificationPreferences.UID_FIELD_NUMBER);
-                boolean userSet = builder.getBoolean(
-                        PackageNotificationPreferences.USER_SET_IMPORTANCE_FIELD_NUMBER);
+        assertEquals("total number of packages", 3, events.size());
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasPackageNotificationPreferences());
+            PackageNotificationPreferences p = atom.getPackageNotificationPreferences();
+            int uid = p.getUid();
 
-                // if it's one of the expected ids, then make sure the importance matches
-                assertTrue(expected.containsKey(uid));
-                assertThat(expected.get(uid).first).isEqualTo(
-                        builder.getInt(PackageNotificationPreferences.IMPORTANCE_FIELD_NUMBER));
-                assertThat(expected.get(uid).second).isEqualTo(userSet);
-            }
+            // if it's one of the expected ids, then make sure the importance matches
+            assertTrue(expected.containsKey(uid));
+            assertThat(expected.get(uid).first).isEqualTo(p.getImportance());
+            assertThat(expected.get(uid).second).isEqualTo(p.getUserSetImportance());
         }
-        // should have at least one entry for each of the packages we expected to see
-        assertThat(found).isAtLeast(3);
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
deleted file mode 100644
index 89adc72..0000000
--- a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.notification;
-
-import android.util.StatsEvent;
-
-import com.android.server.notification.SysUiStatsEvent.Builder;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Wrapper for SysUiStatsEvent that implements validation.
- */
-public class WrappedSysUiStatsEvent {
-
-    static class WrappedBuilder extends Builder {
-        private ArrayList<Object> mValues;
-        private HashMap<Integer, HashMap<Byte, Object>> mAnnotations;
-        private int mAtomId;
-        private int mLastIndex;
-        private boolean mBuilt;
-
-        WrappedBuilder(StatsEvent.Builder builder) {
-            super(builder);
-            mValues = new ArrayList<>();
-            mAnnotations = new HashMap<>();
-            mValues.add(0); // proto fields are 1-based
-        }
-
-        @Override
-        public Builder setAtomId(int atomId) {
-            mAtomId = atomId;
-            super.setAtomId(atomId);
-            return this;
-        }
-
-        @Override
-        public Builder writeInt(int value) {
-            addValue(Integer.valueOf(value));
-            super.writeInt(value);
-            return this;
-        }
-
-        @Override
-        public Builder addBooleanAnnotation(byte annotation, boolean value) {
-            addAnnotation(annotation, Boolean.valueOf(value));
-            super.addBooleanAnnotation(annotation, value);
-            return this;
-        }
-
-        @Override
-        public Builder writeString(String value) {
-            addValue(value);
-            super.writeString(value);
-            return this;
-        }
-
-        @Override
-        public Builder writeBoolean(boolean value) {
-            addValue(Boolean.valueOf(value));
-            super.writeBoolean(value);
-            return this;
-        }
-
-        @Override
-        public StatsEvent build() {
-            mBuilt = true;
-            return super.build();
-        }
-
-        public Object getValue(int index) {
-            return index < mValues.size() ? mValues.get(index) : null;
-        }
-
-        /** useful to make assertTrue() statements more readable. */
-        public boolean getBoolean(int index) {
-            return (Boolean) mValues.get(index);
-        }
-
-        /** useful to make assertTrue() statements more readable. */
-        public int getInt(int index) {
-            return (Integer) mValues.get(index);
-        }
-
-        /** useful to make assertTrue() statements more readable. */
-        public String getString(int index) {
-            return (String) mValues.get(index);
-        }
-
-        private void addValue(Object value) {
-            mLastIndex = mValues.size();
-            mValues.add(value);
-        }
-
-        private void addAnnotation(byte annotation, Object value) {
-            Integer key = Integer.valueOf(mLastIndex);
-            if (!mAnnotations.containsKey(key)) {
-                mAnnotations.put(key, new HashMap<>());
-            }
-            mAnnotations.get(key).put(Byte.valueOf(annotation), value);
-        }
-
-        public boolean getBooleanAnnotation(int i, byte a) {
-            return ((Boolean) mAnnotations.get(Integer.valueOf(i)).get(Byte.valueOf(a)))
-                    .booleanValue();
-        }
-
-        public int getAtomId() {
-            return mAtomId;
-        }
-    }
-
-    static class WrappedBuilderFactory extends SysUiStatsEvent.BuilderFactory {
-        public List<WrappedBuilder> builders;
-
-        WrappedBuilderFactory() {
-            builders = new ArrayList<>();
-        }
-
-        @Override
-        Builder newBuilder() {
-            WrappedBuilder b = new WrappedBuilder(StatsEvent.newBuilder());
-            builders.add(b);
-            return b;
-        }
-    }
-}
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 3ee75de..e22c104 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -33,18 +33,12 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
 import static android.service.notification.Condition.STATE_FALSE;
 import static android.service.notification.Condition.STATE_TRUE;
-import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
 
 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.LOG_DND_STATE_EVENTS;
-import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
-import static com.android.os.dnd.DNDModeProto.CHANNELS_BYPASSING_FIELD_NUMBER;
-import static com.android.os.dnd.DNDModeProto.ENABLED_FIELD_NUMBER;
-import static com.android.os.dnd.DNDModeProto.ID_FIELD_NUMBER;
-import static com.android.os.dnd.DNDModeProto.UID_FIELD_NUMBER;
-import static com.android.os.dnd.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
 import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED;
 import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG;
 import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW;
@@ -73,6 +67,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.SuppressLint;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.AutomaticZenRule;
@@ -106,6 +101,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.StatsEvent;
+import android.util.StatsEventTestUtils;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -113,12 +109,15 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
+import com.android.os.AtomsProto;
+import com.android.os.dnd.DNDModeProto;
 import com.android.os.dnd.DNDPolicyProto;
 import com.android.os.dnd.DNDProtoEnums;
 import com.android.server.UiServiceTestCase;
 import com.android.server.notification.ManagedServices.UserProfiles;
 
 import com.google.common.collect.ImmutableList;
+import com.google.protobuf.InvalidProtocolBufferException;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -140,13 +139,13 @@
 import java.util.Objects;
 
 @SmallTest
+@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class ZenModeHelperTest extends UiServiceTestCase {
 
     private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
     private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
-    private static final int ZEN_MODE_FOR_TESTING = 99;
     private static final String CUSTOM_PKG_NAME = "not.android";
     private static final int CUSTOM_PKG_UID = 1;
     private static final String CUSTOM_RULE_ID = "custom_rule";
@@ -159,7 +158,6 @@
     private ZenModeHelper mZenModeHelper;
     private ContentResolver mContentResolver;
     @Mock AppOpsManager mAppOps;
-    private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
     TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
     ZenModeEventLoggerFake mZenModeEventLogger;
 
@@ -178,7 +176,6 @@
             Log.d("ZenModeHelperTest", "Couldn't mock default zen mode config xml file err=" +
                     e.toString());
         }
-        mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
 
         when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps);
         when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
@@ -188,8 +185,7 @@
         mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
         mZenModeEventLogger = new ZenModeEventLoggerFake(mPackageManager);
         mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(),
-                mConditionProviders, mStatsEventBuilderFactory, mTestFlagResolver,
-                mZenModeEventLogger);
+                mConditionProviders, mTestFlagResolver, mZenModeEventLogger);
 
         ResolveInfo ri = new ResolveInfo();
         ri.activityInfo = new ActivityInfo();
@@ -911,37 +907,35 @@
     }
 
     @Test
-    public void testProto() {
+    public void testProto() throws InvalidProtocolBufferException {
         mZenModeHelper.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         // existence of manual rule means it should be in output
         mZenModeHelper.mConfig.manualRule = new ZenModeConfig.ZenRule();
         mZenModeHelper.mConfig.manualRule.pkg = "android";  // system
+        mZenModeHelper.mConfig.automaticRules = new ArrayMap<>(); // no automatic rules
 
-        int n = mZenModeHelper.mConfig.automaticRules.size();
-        List<String> ids = new ArrayList<>(n);
-        for (ZenModeConfig.ZenRule rule : mZenModeHelper.mConfig.automaticRules.values()) {
-            ids.add(rule.id);
-        }
+        List<String> ids = new ArrayList<>();
         ids.add(ZenModeConfig.MANUAL_RULE_ID);
         ids.add(""); // for ROOT_CONFIG, logged with empty string as id
 
         List<StatsEvent> events = new LinkedList<>();
         mZenModeHelper.pullRules(events);
-        assertEquals(n + 2, events.size());  // automatic rules + manual rule + root config
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == DND_MODE_RULE) {
-                if (builder.getInt(ZEN_MODE_FIELD_NUMBER) == ROOT_CONFIG) {
-                    assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
-                    assertFalse(builder.getBoolean(CHANNELS_BYPASSING_FIELD_NUMBER));
-                }
-                assertEquals(Process.SYSTEM_UID, builder.getInt(UID_FIELD_NUMBER));
-                assertTrue(builder.getBooleanAnnotation(UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID));
-                String name = (String) builder.getValue(ID_FIELD_NUMBER);
-                assertTrue("unexpected rule id", ids.contains(name));
-                ids.remove(name);
-            } else {
-                fail("unexpected atom id: " + builder.getAtomId());
+        assertEquals(2, events.size());  // manual rule + root config
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasDndModeRule());
+            DNDModeProto cfg = atom.getDndModeRule();
+            // Additional check for ID to clearly identify the root config because there's some
+            // odd behavior in the test util around enum value of 0 (the usual default, but not in
+            // this case).
+            if (cfg.getZenMode().getNumber() == ROOT_CONFIG && cfg.getId().equals("")) {
+                assertTrue(cfg.getEnabled());
+                assertFalse(cfg.getChannelsBypassing());
             }
+            assertEquals(Process.SYSTEM_UID, cfg.getUid());
+            String name = cfg.getId();
+            assertTrue("unexpected rule id", ids.contains(name));
+            ids.remove(name);
         }
         assertEquals("extra rule in output", 0, ids.size());
     }
@@ -949,28 +943,61 @@
     @Test
     public void testProtoWithAutoRule() throws Exception {
         setupZenConfig();
-        // one enabled automatic rule
-        mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_FOR_TESTING);
+        // one enabled automatic rule. we use a non-usual zen mode value (though it has to be
+        // a real one in the enum because non-valid enum values are reverted to default).
+        mZenModeHelper.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_ALARMS);
 
         List<StatsEvent> events = new LinkedList<>();
         mZenModeHelper.pullRules(events);
 
         boolean foundCustomEvent = false;
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == DND_MODE_RULE) {
-                if (ZEN_MODE_FOR_TESTING == builder.getInt(ZEN_MODE_FIELD_NUMBER)) {
-                    foundCustomEvent = true;
-                    assertEquals(CUSTOM_PKG_UID, builder.getInt(UID_FIELD_NUMBER));
-                    assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
-                }
-            } else {
-                fail("unexpected atom id: " + builder.getAtomId());
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasDndModeRule());
+            DNDModeProto cfg = atom.getDndModeRule();
+            if (cfg.getZenMode().getNumber() == ZEN_MODE_ALARMS) {
+                foundCustomEvent = true;
+                assertEquals(CUSTOM_PKG_UID, cfg.getUid());
+                assertTrue(cfg.getEnabled());
             }
         }
         assertTrue("couldn't find custom rule", foundCustomEvent);
     }
 
     @Test
+    public void testProtoWithDefaultAutoRules() throws Exception {
+        setupZenConfig();
+        // clear the automatic rules so we can reset to only the default rules
+        mZenModeHelper.mConfig.automaticRules = new ArrayMap<>();
+
+        // read in XML to restore the default rules
+        ByteArrayOutputStream baos = writeXmlAndPurge(5);
+        TypedXmlPullParser parser = Xml.newFastPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(baos.toByteArray())), null);
+        parser.nextTag();
+        mZenModeHelper.readXml(parser, false, UserHandle.USER_ALL);
+        List<StatsEvent> events = new LinkedList<>();
+        mZenModeHelper.pullRules(events);
+
+        // list for tracking which ids we've seen in the pulled atom output
+        List<String> ids = new ArrayList<>();
+        ids.addAll(ZenModeConfig.DEFAULT_RULE_IDS);
+        ids.add("");  // empty string for root config
+
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasDndModeRule());
+            DNDModeProto cfg = atom.getDndModeRule();
+            if (!ids.contains(cfg.getId())) {
+                fail("unexpected ID found: " + cfg.getId());
+            }
+            ids.remove(cfg.getId());
+        }
+        assertEquals("default ID(s) not found", 0, ids.size());
+    }
+
+    @Test
     public void ruleUidsCached() throws Exception {
         setupZenConfig();
         // one enabled automatic rule
@@ -1019,10 +1046,11 @@
         List<StatsEvent> events = new LinkedList<>();
         mZenModeHelper.pullRules(events);
 
-        boolean foundCustomEvent = false;
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == DND_MODE_RULE
-                    && "customRule".equals(builder.getString(ID_FIELD_NUMBER))) {
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasDndModeRule());
+            DNDModeProto cfg = atom.getDndModeRule();
+            if ("customRule".equals(cfg.getId())) {
                 fail("non-default IDs should be redacted");
             }
         }
@@ -1039,14 +1067,17 @@
         mZenModeHelper.pullRules(events);
 
         boolean foundManualRule = false;
-        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
-            if (builder.getAtomId() == DND_MODE_RULE
-                    && ZenModeConfig.MANUAL_RULE_ID.equals(builder.getString(ID_FIELD_NUMBER))) {
-                assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+        for (StatsEvent ev : events) {
+            AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev);
+            assertTrue(atom.hasDndModeRule());
+            DNDModeProto cfg = atom.getDndModeRule();
+            if (ZenModeConfig.MANUAL_RULE_ID.equals(cfg.getId())) {
+                assertEquals(0, cfg.getUid());
                 foundManualRule = true;
             }
         }
-        assertTrue("couldn't find manual rule", foundManualRule);    }
+        assertTrue("couldn't find manual rule", foundManualRule);
+    }
 
     @Test
     public void testWriteXml_onlyBackupsTargetUser() throws Exception {
@@ -2439,6 +2470,143 @@
         assertEquals(12345, mZenModeEventLogger.getPackageUid(4));
     }
 
+    @Test
+    public void testUpdateConsolidatedPolicy_defaultRulesOnly() {
+        setupZenConfig();
+
+        // When there's one automatic rule active and it doesn't specify a policy, test that the
+        // resulting consolidated policy is one that matches the default rule settings.
+        AutomaticZenRule zenRule = new AutomaticZenRule("name",
+                null,
+                new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+                ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+                null,
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+        String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
+                Process.SYSTEM_UID, true);
+
+        // enable the rule
+        mZenModeHelper.setAutomaticZenRuleState(id,
+                new Condition(zenRule.getConditionId(), "", STATE_TRUE),
+                Process.SYSTEM_UID, true);
+
+        // inspect the consolidated policy. Based on setupZenConfig() values.
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowAlarms());
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowMedia());
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem());
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowReminders());
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowCalls());
+        assertEquals(PRIORITY_SENDERS_STARRED, mZenModeHelper.mConsolidatedPolicy.allowCallsFrom());
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMessages());
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowConversations());
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers());
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.showBadges());
+    }
+
+    @Test
+    public void testUpdateConsolidatedPolicy_customPolicyOnly() {
+        setupZenConfig();
+
+        // when there's only one automatic rule active and it has a custom policy, make sure that's
+        // what the consolidated policy reflects whether or not it's stricter than what the default
+        // would specify.
+        ZenPolicy customPolicy = new ZenPolicy.Builder()
+                .allowAlarms(true)  // more lenient than default
+                .allowMedia(true)  // more lenient than default
+                .allowRepeatCallers(false)  // more restrictive than default
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE)  // more restrictive than default
+                .showBadges(true)  // more lenient
+                .showPeeking(false)  // more restrictive
+                .build();
+
+        AutomaticZenRule zenRule = new AutomaticZenRule("name",
+                null,
+                new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+                ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+                customPolicy,
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+        String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
+                Process.SYSTEM_UID, true);
+
+        // enable the rule; this will update the consolidated policy
+        mZenModeHelper.setAutomaticZenRuleState(id,
+                new Condition(zenRule.getConditionId(), "", STATE_TRUE),
+                Process.SYSTEM_UID, true);
+
+        // since this is the only active rule, the consolidated policy should match the custom
+        // policy for every field specified, and take default values for unspecified things
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowAlarms());  // custom
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMedia());  // custom
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem());  // default
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowReminders());  // default
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowCalls());  // custom
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMessages()); // default
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowConversations());  // default
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers());  // custom
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.showBadges());  // custom
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.showPeeking());  // custom
+    }
+
+    @Test
+    public void testUpdateConsolidatedPolicy_defaultAndCustomActive() {
+        setupZenConfig();
+
+        // when there are two rules active, one inheriting the default policy and one setting its
+        // own custom policy, they should be merged to form the most restrictive combination.
+
+        // rule 1: no custom policy
+        AutomaticZenRule zenRule = new AutomaticZenRule("name",
+                null,
+                new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+                ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+                null,
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+        String id = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule, "test",
+                Process.SYSTEM_UID, true);
+
+        // enable rule 1
+        mZenModeHelper.setAutomaticZenRuleState(id,
+                new Condition(zenRule.getConditionId(), "", STATE_TRUE),
+                Process.SYSTEM_UID, true);
+
+        // custom policy for rule 2
+        ZenPolicy customPolicy = new ZenPolicy.Builder()
+                .allowAlarms(true)  // more lenient than default
+                .allowMedia(true)  // more lenient than default
+                .allowRepeatCallers(false)  // more restrictive than default
+                .allowCalls(ZenPolicy.PEOPLE_TYPE_NONE)  // more restrictive than default
+                .showBadges(true)  // more lenient
+                .showPeeking(false)  // more restrictive
+                .build();
+
+        AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
+                null,
+                new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider"),
+                ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+                customPolicy,
+                NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+        String id2 = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), zenRule2,
+                "test", Process.SYSTEM_UID, true);
+
+        // enable rule 2; this will update the consolidated policy
+        mZenModeHelper.setAutomaticZenRuleState(id2,
+                new Condition(zenRule2.getConditionId(), "", STATE_TRUE),
+                Process.SYSTEM_UID, true);
+
+        // now both rules should be on, and the consolidated policy should reflect the most
+        // restrictive option of each of the two
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowAlarms());  // default stricter
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowMedia());  // default stricter
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowSystem());  // default, unset in custom
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowReminders());  // default
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowCalls());  // custom stricter
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowMessages()); // default, unset in custom
+        assertTrue(mZenModeHelper.mConsolidatedPolicy.allowConversations());  // default
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.allowRepeatCallers());  // custom stricter
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.showBadges());  // default stricter
+        assertFalse(mZenModeHelper.mConsolidatedPolicy.showPeeking());  // custom stricter
+    }
+
     private void setupZenConfig() {
         mZenModeHelper.mZenMode = Global.ZEN_MODE_OFF;
         mZenModeHelper.mConfig.allowAlarms = false;
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java
index 10b49c6..bc826a3 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackCustomizationTest.java
@@ -30,7 +30,6 @@
 
 import android.content.res.Resources;
 import android.os.VibrationEffect;
-import android.os.Vibrator;
 import android.os.VibratorInfo;
 import android.util.AtomicFile;
 import android.util.SparseArray;
@@ -73,12 +72,10 @@
             VibrationEffect.createWaveform(new long[] {123}, new int[] {254}, -1);
 
     @Mock private Resources mResourcesMock;
-    @Mock private Vibrator mVibratorMock;
     @Mock private VibratorInfo mVibratorInfoMock;
 
     @Before
     public void setUp() {
-        when(mVibratorMock.getInfo()).thenReturn(mVibratorInfoMock);
         when(mVibratorInfoMock.areVibrationFeaturesSupported(any())).thenReturn(true);
     }
 
@@ -220,17 +217,17 @@
     public void testParseCustomizations_noCustomizationFile_returnsNull() throws Exception {
         setCustomizationFilePath("");
 
-        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorMock))
+        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorInfoMock))
                 .isNull();
 
         setCustomizationFilePath(null);
 
-        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorMock))
+        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorInfoMock))
                 .isNull();
 
         setCustomizationFilePath("non_existent_file.xml");
 
-        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorMock))
+        assertThat(HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorInfoMock))
                 .isNull();
     }
 
@@ -387,7 +384,7 @@
             String xml, SparseArray<VibrationEffect> expectedCustomizations) throws Exception {
         setupCustomizationFile(xml);
         assertThat(expectedCustomizations.contentEquals(
-                HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorMock)))
+                HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorInfoMock)))
                         .isTrue();
     }
 
@@ -395,13 +392,15 @@
         setupCustomizationFile(xml);
         assertThrows("Expected haptic feedback customization to fail for " + xml,
                 CustomizationParserException.class,
-                () ->  HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorMock));
+                () ->  HapticFeedbackCustomization.loadVibrations(
+                        mResourcesMock, mVibratorInfoMock));
     }
 
     private void assertParseCustomizationsFails() throws Exception {
         assertThrows("Expected haptic feedback customization to fail",
                 CustomizationParserException.class,
-                () ->  HapticFeedbackCustomization.loadVibrations(mResourcesMock, mVibratorMock));
+                () ->  HapticFeedbackCustomization.loadVibrations(
+                        mResourcesMock, mVibratorInfoMock));
     }
 
     private void setupCustomizationFile(String xml) throws Exception {
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 cae811e..a91bd2b 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/HapticFeedbackVibrationProviderTest.java
@@ -31,8 +31,10 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.hardware.vibrator.IVibrator;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
-import android.os.test.FakeVibrator;
+import android.os.VibratorInfo;
 import android.util.AtomicFile;
 import android.util.SparseArray;
 
@@ -58,7 +60,7 @@
             VibrationEffect.startComposition().addPrimitive(PRIMITIVE_CLICK, 0.3497f).compose();
 
     private Context mContext = InstrumentationRegistry.getContext();
-    private FakeVibrator mVibrator = new FakeVibrator(mContext);
+    private VibratorInfo mVibratorInfo = VibratorInfo.EMPTY_VIBRATOR_INFO;
 
     @Mock private Resources mResourcesMock;
 
@@ -66,14 +68,14 @@
     public void testNonExistentCustomization_useDefault() throws Exception {
         // No customization file is set.
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
                 .isEqualTo(VibrationEffect.get(EFFECT_TICK));
 
         // The customization file specifies no customization.
         setupCustomizationFile("<haptic-feedback-constants></haptic-feedback-constants>");
-        hapticProvider = new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator);
+        hapticProvider = new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
                 .isEqualTo(VibrationEffect.get(EFFECT_TICK));
@@ -83,7 +85,7 @@
     public void testExceptionParsingCustomizations_useDefault() throws Exception {
         setupCustomizationFile("<bad-xml></bad-xml>");
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
                 .isEqualTo(VibrationEffect.get(EFFECT_TICK));
@@ -96,7 +98,7 @@
         customizations.put(CONTEXT_CLICK, PRIMITIVE_CLICK_EFFECT);
 
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
 
         // The override for `CONTEXT_CLICK` is used.
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
@@ -109,11 +111,15 @@
     @Test
     public void testDoNotUseInvalidCustomizedVibration() throws Exception {
         mockVibratorPrimitiveSupport(new int[] {});
-        SparseArray<VibrationEffect> customizations = new SparseArray<>();
-        customizations.put(CONTEXT_CLICK, PRIMITIVE_CLICK_EFFECT);
+        String xml = "<haptic-feedback-constants>"
+                + "<constant id=\"" + CONTEXT_CLICK + "\">"
+                + PRIMITIVE_CLICK_EFFECT
+                + "</constant>"
+                + "</haptic-feedback-constants>";
+        setupCustomizationFile(xml);
 
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
 
         // The override for `CONTEXT_CLICK` is not used because the vibration is not supported.
         assertThat(hapticProvider.getVibrationForHapticFeedback(CONTEXT_CLICK))
@@ -132,14 +138,14 @@
 
         // Test with a customization available for `TEXT_HANDLE_MOVE`.
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE)).isNull();
 
         // Test with no customization available for `TEXT_HANDLE_MOVE`.
         hapticProvider =
                 new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibrator, /* hapticCustomizations= */ null);
+                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE)).isNull();
     }
@@ -153,7 +159,7 @@
 
         // Test with a customization available for `TEXT_HANDLE_MOVE`.
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE))
                 .isEqualTo(PRIMITIVE_CLICK_EFFECT);
@@ -161,7 +167,7 @@
         // Test with no customization available for `TEXT_HANDLE_MOVE`.
         hapticProvider =
                 new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibrator, /* hapticCustomizations= */ null);
+                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(TEXT_HANDLE_MOVE))
                 .isEqualTo(VibrationEffect.get(EFFECT_TEXTURE_TICK));
@@ -176,14 +182,14 @@
         customizations.put(SAFE_MODE_ENABLED, PRIMITIVE_CLICK_EFFECT);
 
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
                 .isEqualTo(PRIMITIVE_CLICK_EFFECT);
 
         mockSafeModeEnabledVibration(null);
         hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo, customizations);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
                 .isEqualTo(PRIMITIVE_CLICK_EFFECT);
@@ -193,20 +199,9 @@
     public void testNoValidCustomizationPresentForSafeModeEnabled_resourceBasedVibrationUsed()
                 throws Exception {
         mockSafeModeEnabledVibration(10, 20, 30, 40);
-        SparseArray<VibrationEffect> customizations = new SparseArray<>();
-        customizations.put(SAFE_MODE_ENABLED, PRIMITIVE_CLICK_EFFECT);
-
-        // Test with a customization that is not supported by the vibrator.
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
-
-        assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
-                .isEqualTo(VibrationEffect.createWaveform(new long[] {10, 20, 30, 40}, -1));
-
-        // Test with no customizations.
-        hapticProvider =
                 new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibrator, /* hapticCustomizations= */ null);
+                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED))
                 .isEqualTo(VibrationEffect.createWaveform(new long[] {10, 20, 30, 40}, -1));
@@ -216,25 +211,44 @@
     public void testNoValidCustomizationAndResourcePresentForSafeModeEnabled_noVibrationUsed()
                 throws Exception {
         mockSafeModeEnabledVibration(null);
-        SparseArray<VibrationEffect> customizations = new SparseArray<>();
-        customizations.put(SAFE_MODE_ENABLED, PRIMITIVE_CLICK_EFFECT);
-
-        // Test with a customization that is not supported by the vibrator.
         HapticFeedbackVibrationProvider hapticProvider =
-                new HapticFeedbackVibrationProvider(mResourcesMock, mVibrator, customizations);
-
-        assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED)).isNull();
-
-        // Test with no customizations.
-        hapticProvider =
                 new HapticFeedbackVibrationProvider(
-                        mResourcesMock, mVibrator, /* hapticCustomizations= */ null);
+                        mResourcesMock, mVibratorInfo, /* hapticCustomizations= */ null);
 
         assertThat(hapticProvider.getVibrationForHapticFeedback(SAFE_MODE_ENABLED)).isNull();
     }
 
+    @Test
+    public void testVibrationAttribute_forNotBypassingIntensitySettings() {
+        HapticFeedbackVibrationProvider hapticProvider =
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+
+        VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
+                SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ false);
+
+        assertThat(attrs.getFlags() & VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
+                .isEqualTo(0);
+    }
+
+    @Test
+    public void testVibrationAttribute_forByassingIntensitySettings() {
+        HapticFeedbackVibrationProvider hapticProvider =
+                new HapticFeedbackVibrationProvider(mResourcesMock, mVibratorInfo);
+
+        VibrationAttributes attrs = hapticProvider.getVibrationAttributesForHapticFeedback(
+                SAFE_MODE_ENABLED, /* bypassVibrationIntensitySetting= */ true);
+
+        assertThat(attrs.getFlags() & VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF)
+                .isNotEqualTo(0);
+    }
+
     private void mockVibratorPrimitiveSupport(int... supportedPrimitives) {
-        mVibrator = new FakeVibrator(mContext, supportedPrimitives);
+        VibratorInfo.Builder builder = new VibratorInfo.Builder(/* id= */ 1)
+                .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        for (int primitive : supportedPrimitives) {
+            builder.setSupportedPrimitive(primitive, 10);
+        }
+        mVibratorInfo = builder.build();
     }
 
     private void mockHapticTextSupport(boolean supported) {
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 44cf333..085241f 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -63,7 +63,6 @@
 import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
 
 import com.android.server.LocalServices;
@@ -1005,7 +1004,6 @@
                 mVibratorProviders.get(3).getEffectSegments(vibrationId));
     }
 
-    @FlakyTest
     @Test
     public void vibrate_multipleSyncedCallbackTriggered_finishSteps() throws Exception {
         int[] vibratorIds = new int[]{1, 2};
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 4e3a893..c25f0cb 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -30,6 +31,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -45,6 +47,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManagerInternal;
+import android.content.res.Resources;
 import android.hardware.input.IInputManager;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerGlobal;
@@ -79,8 +82,10 @@
 import android.os.vibrator.VibrationEffectSegment;
 import android.provider.Settings;
 import android.util.ArraySet;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.Display;
+import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
 
 import androidx.test.InstrumentationRegistry;
@@ -169,6 +174,8 @@
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
 
+    private SparseArray<VibrationEffect>  mHapticFeedbackVibrationMap = new SparseArray<>();
+
     private VibratorManagerService mService;
     private Context mContextSpy;
     private TestLooper mTestLooper;
@@ -309,6 +316,12 @@
                         mExternalVibratorService =
                                 (VibratorManagerService.ExternalVibratorService) serviceInstance;
                     }
+
+                    HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
+                            Resources resources, VibratorInfo vibratorInfo) {
+                        return new HapticFeedbackVibrationProvider(
+                                resources, vibratorInfo, mHapticFeedbackVibrationMap);
+                    }
                 });
         return mService;
     }
@@ -623,6 +636,18 @@
     }
 
     @Test
+    public void vibrate_withoutVibratePermission_throwsSecurityException() {
+        denyPermission(android.Manifest.permission.VIBRATE);
+        VibratorManagerService service = createSystemReadyService();
+
+        assertThrows("Expected vibrating without permission to fail!",
+                SecurityException.class,
+                () -> vibrate(service,
+                        VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK),
+                        VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH)));
+    }
+
+    @Test
     public void vibrate_withRingtone_usesRingerModeSettings() throws Exception {
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
@@ -1274,6 +1299,60 @@
     }
 
     @Test
+    public void performHapticFeedback_doesNotRequirePermission() throws Exception {
+        denyPermission(android.Manifest.permission.VIBRATE);
+        mHapticFeedbackVibrationMap.put(
+                HapticFeedbackConstants.KEYBOARD_TAP,
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        mockVibrators(1);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        VibratorManagerService service = createSystemReadyService();
+
+        HalVibration vibration =
+                performHapticFeedbackAndWaitUntilFinished(
+                        service, HapticFeedbackConstants.KEYBOARD_TAP, /* always= */ true);
+
+        List<VibrationEffectSegment> playedSegments = fakeVibrator.getAllEffectSegments();
+        assertEquals(1, playedSegments.size());
+        PrebakedSegment segment = (PrebakedSegment) playedSegments.get(0);
+        assertEquals(VibrationEffect.EFFECT_CLICK, segment.getEffectId());
+        assertEquals(VibrationAttributes.USAGE_TOUCH, vibration.callerInfo.attrs.getUsage());
+    }
+
+    @Test
+    public void performHapticFeedback_doesNotVibrateWhenVibratorInfoNotReady() throws Exception {
+        denyPermission(android.Manifest.permission.VIBRATE);
+        mHapticFeedbackVibrationMap.put(
+                HapticFeedbackConstants.KEYBOARD_TAP,
+                VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
+        mockVibrators(1);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setVibratorInfoLoadSuccessful(false);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        VibratorManagerService service = createService();
+
+        performHapticFeedbackAndWaitUntilFinished(
+                service, HapticFeedbackConstants.KEYBOARD_TAP, /* always= */ true);
+
+        assertTrue(fakeVibrator.getAllEffectSegments().isEmpty());
+    }
+
+    @Test
+    public void performHapticFeedback_doesNotVibrateForInvalidConstant() throws Exception {
+        denyPermission(android.Manifest.permission.VIBRATE);
+        mockVibrators(1);
+        VibratorManagerService service = createSystemReadyService();
+
+        // These are bad haptic feedback IDs, so expect no vibration played.
+        performHapticFeedbackAndWaitUntilFinished(service, /* constant= */ -1, /* always= */ false);
+        performHapticFeedbackAndWaitUntilFinished(
+                service, HapticFeedbackConstants.NO_HAPTICS, /* always= */ true);
+
+        assertTrue(mVibratorProviders.get(1).getAllEffectSegments().isEmpty());
+    }
+
+    @Test
     public void vibrate_withIntensitySettings_appliesSettingsToScaleVibrations() throws Exception {
         int defaultNotificationIntensity =
                 mVibrator.getDefaultVibrationIntensity(VibrationAttributes.USAGE_NOTIFICATION);
@@ -2231,6 +2310,18 @@
                 mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
     }
 
+    private HalVibration performHapticFeedbackAndWaitUntilFinished(VibratorManagerService service,
+                int constant, boolean always) throws InterruptedException {
+        HalVibration vib =
+                service.performHapticFeedbackInternal(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME,
+                        constant, always, "some reason", service);
+        if (vib != null) {
+            vib.waitForEnd();
+        }
+
+        return vib;
+    }
+
     private void vibrateAndWaitUntilFinished(VibratorManagerService service, VibrationEffect effect,
             VibrationAttributes attrs) throws InterruptedException {
         vibrateAndWaitUntilFinished(service, CombinedVibration.createParallel(effect), attrs);
@@ -2239,8 +2330,8 @@
     private void vibrateAndWaitUntilFinished(VibratorManagerService service,
             CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
         HalVibration vib =
-                service.vibrateInternal(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME, effect, attrs,
-                        "some reason", service);
+                service.vibrateWithPermissionCheck(UID, Display.DEFAULT_DISPLAY, PACKAGE_NAME,
+                        effect, attrs, "some reason", service);
         if (vib != null) {
             vib.waitForEnd();
         }
@@ -2271,4 +2362,9 @@
         }
         return predicateResult;
     }
+
+    private void denyPermission(String permission) {
+        doThrow(new SecurityException()).when(mContextSpy)
+                .enforceCallingOrSelfPermission(eq(permission), anyString());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index f83aecb..8db09f9 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -115,43 +115,61 @@
         }
     }
 
-    void sendKeyCombination(int[] keyCodes, long duration) {
+    void sendKeyCombination(int[] keyCodes, long duration, boolean longPress) {
         final long downTime = SystemClock.uptimeMillis();
         final int count = keyCodes.length;
-        final KeyEvent[] events = new KeyEvent[count];
         int metaState = 0;
+
         for (int i = 0; i < count; i++) {
             final int keyCode = keyCodes[i];
             final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
                     0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
                     0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
             event.setDisplayId(DEFAULT_DISPLAY);
-            events[i] = event;
+            interceptKey(event);
             // The order is important here, metaState could be updated and applied to the next key.
             metaState |= MODIFIER.getOrDefault(keyCode, 0);
         }
 
-        for (KeyEvent event: events) {
-            interceptKey(event);
-        }
-
         try {
             Thread.sleep(duration);
         } catch (InterruptedException e) {
             throw new RuntimeException(e);
         }
 
+        if (longPress) {
+            final long nextDownTime = SystemClock.uptimeMillis();
+            for (int i = 0; i < count; i++) {
+                final int keyCode = keyCodes[i];
+                final KeyEvent nextDownEvent = new KeyEvent(downTime, nextDownTime,
+                        KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, metaState,
+                        KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+                        KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD);
+                nextDownEvent.setDisplayId(DEFAULT_DISPLAY);
+                interceptKey(nextDownEvent);
+            }
+        }
+
+        final long eventTime = SystemClock.uptimeMillis();
         for (int i = count - 1; i >= 0; i--) {
-            final long eventTime = SystemClock.uptimeMillis();
             final int keyCode = keyCodes[i];
             final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
                     0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
                     InputDevice.SOURCE_KEYBOARD);
+            upEvent.setDisplayId(DEFAULT_DISPLAY);
             interceptKey(upEvent);
             metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
         }
     }
 
+    void sendKeyCombination(int[] keyCodes, long duration) {
+        sendKeyCombination(keyCodes, duration, false /* longPress */);
+    }
+
+    void sendLongPressKeyCombination(int[] keyCodes) {
+        sendKeyCombination(keyCodes, ViewConfiguration.getLongPressTimeout(), true /* longPress */);
+    }
+
     void sendKey(int keyCode) {
         sendKey(keyCode, false);
     }
@@ -179,6 +197,7 @@
         final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
                 0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
                 0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
+        upEvent.setDisplayId(DEFAULT_DISPLAY);
         interceptKey(upEvent);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
index 8fadecd..4791946 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
@@ -16,6 +16,11 @@
 
 package com.android.server.policy;
 
+import static com.android.server.policy.PhoneWindowManager.DOUBLE_TAP_HOME_RECENT_SYSTEM_UI;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ALL_APPS;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_ASSIST;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_HOME_NOTIFICATION_PANEL;
+
 import android.platform.test.annotations.Presubmit;
 import android.view.KeyEvent;
 
@@ -65,6 +70,12 @@
                         KeyboardLogEvent.RECENT_APPS, KeyEvent.KEYCODE_TAB, ALT_ON},
                 {"BACK key -> Go back", new int[]{KeyEvent.KEYCODE_BACK}, KeyboardLogEvent.BACK,
                         KeyEvent.KEYCODE_BACK, 0},
+                {"Meta + `(grave) -> Go back", new int[]{META_KEY, KeyEvent.KEYCODE_GRAVE},
+                        KeyboardLogEvent.BACK, KeyEvent.KEYCODE_GRAVE, META_ON},
+                {"Meta + Left arrow -> Go back", new int[]{META_KEY, KeyEvent.KEYCODE_DPAD_LEFT},
+                        KeyboardLogEvent.BACK, KeyEvent.KEYCODE_DPAD_LEFT, META_ON},
+                {"Meta + Del -> Go back", new int[]{META_KEY, KeyEvent.KEYCODE_DEL},
+                        KeyboardLogEvent.BACK, KeyEvent.KEYCODE_DEL, META_ON},
                 {"APP_SWITCH key -> Open App switcher", new int[]{KeyEvent.KEYCODE_APP_SWITCH},
                         KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_APP_SWITCH, 0},
                 {"ASSIST key -> Launch assistant", new int[]{KeyEvent.KEYCODE_ASSIST},
@@ -220,6 +231,59 @@
                         KeyboardLogEvent.LAUNCH_DEFAULT_MESSAGING, KeyEvent.KEYCODE_S, META_ON}};
     }
 
+    @Keep
+    private static Object[][] longPressOnHomeTestArguments() {
+        // testName, testKeys, longPressOnHomeBehavior, expectedLogEvent, expectedKey,
+        // expectedModifierState
+        return new Object[][]{
+                {"Long press HOME key -> Toggle Notification panel",
+                        new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_HOME, 0},
+                {"Long press META + ENTER -> Toggle Notification panel",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER},
+                        LONG_PRESS_HOME_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_ENTER,
+                        META_ON},
+                {"Long press META + H -> Toggle Notification panel",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_NOTIFICATION_PANEL,
+                        KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_H, META_ON},
+                {"Long press HOME key -> Launch assistant",
+                        new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ASSIST,
+                        KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_HOME, 0},
+                {"Long press META + ENTER -> Launch assistant",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ASSIST,
+                        KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_ENTER, META_ON},
+                {"Long press META + H -> Launch assistant",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_H}, LONG_PRESS_HOME_ASSIST,
+                        KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_H, META_ON},
+                {"Long press HOME key -> Open App Drawer",
+                        new int[]{KeyEvent.KEYCODE_HOME}, LONG_PRESS_HOME_ALL_APPS,
+                        KeyboardLogEvent.ALL_APPS, KeyEvent.KEYCODE_HOME, 0},
+                {"Long press META + ENTER -> Open App Drawer",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER}, LONG_PRESS_HOME_ALL_APPS,
+                        KeyboardLogEvent.ALL_APPS, KeyEvent.KEYCODE_ENTER, META_ON},
+                {"Long press META + H -> Open App Drawer", new int[]{META_KEY, KeyEvent.KEYCODE_H},
+                        LONG_PRESS_HOME_ALL_APPS, KeyboardLogEvent.ALL_APPS,
+                        KeyEvent.KEYCODE_H, META_ON}};
+    }
+
+    @Keep
+    private static Object[][] doubleTapOnHomeTestArguments() {
+        // testName, testKeys, doubleTapOnHomeBehavior, expectedLogEvent, expectedKey,
+        // expectedModifierState
+        return new Object[][]{
+                {"Double tap HOME -> Open App switcher",
+                        new int[]{KeyEvent.KEYCODE_HOME}, DOUBLE_TAP_HOME_RECENT_SYSTEM_UI,
+                        KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_HOME, 0},
+                {"Double tap META + ENTER -> Open App switcher",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_ENTER},
+                        DOUBLE_TAP_HOME_RECENT_SYSTEM_UI, KeyboardLogEvent.APP_SWITCH,
+                        KeyEvent.KEYCODE_ENTER, META_ON},
+                {"Double tap META + H -> Open App switcher",
+                        new int[]{META_KEY, KeyEvent.KEYCODE_H}, DOUBLE_TAP_HOME_RECENT_SYSTEM_UI,
+                        KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_H, META_ON}};
+    }
+
     @Before
     public void setUp() {
         setUpPhoneWindowManager(/*supportSettingsUpdate*/ true);
@@ -231,13 +295,37 @@
         mPhoneWindowManager.overrideStatusBarManagerInternal();
         mPhoneWindowManager.overrideStartActivity();
         mPhoneWindowManager.overrideUserSetupComplete();
+        mPhoneWindowManager.setupAssistForLaunch();
+        mPhoneWindowManager.overrideTogglePanel();
     }
 
     @Test
     @Parameters(method = "shortcutTestArguments")
     public void testShortcuts(String testName, int[] testKeys, KeyboardLogEvent expectedLogEvent,
             int expectedKey, int expectedModifierState) {
-        sendKeyCombination(testKeys, 0);
+        sendKeyCombination(testKeys, 0 /* duration */);
+        mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
+                expectedKey, expectedModifierState, "Failed while executing " + testName);
+    }
+
+    @Test
+    @Parameters(method = "longPressOnHomeTestArguments")
+    public void testLongPressOnHome(String testName, int[] testKeys, int longPressOnHomeBehavior,
+            KeyboardLogEvent expectedLogEvent, int expectedKey, int expectedModifierState) {
+        mPhoneWindowManager.overrideLongPressOnHomeBehavior(longPressOnHomeBehavior);
+        sendLongPressKeyCombination(testKeys);
+        mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
+                expectedKey, expectedModifierState, "Failed while executing " + testName);
+    }
+
+    @Test
+    @Parameters(method = "doubleTapOnHomeTestArguments")
+    public void testDoubleTapOnHomeBehavior(String testName, int[] testKeys,
+            int doubleTapOnHomeBehavior, KeyboardLogEvent expectedLogEvent, int expectedKey,
+            int expectedModifierState) {
+        mPhoneWindowManager.overriderDoubleTapOnHomeBehavior(doubleTapOnHomeBehavior);
+        sendKeyCombination(testKeys, 0 /* duration */);
+        sendKeyCombination(testKeys, 0 /* duration */);
         mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
                 expectedKey, expectedModifierState, "Failed while executing " + testName);
     }
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index bc8f06a..e301da7 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -364,6 +364,14 @@
         }
     }
 
+    void overrideLongPressOnHomeBehavior(int behavior) {
+        mPhoneWindowManager.mLongPressOnHomeBehavior = behavior;
+    }
+
+    void overriderDoubleTapOnHomeBehavior(int behavior) {
+        mPhoneWindowManager.mDoubleTapOnHomeBehavior = behavior;
+    }
+
     void overrideCanStartDreaming(boolean canDream) {
         doReturn(canDream).when(mDreamManagerInternal).canStartDreaming(anyBoolean());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 302ad7f..31682bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1541,7 +1541,8 @@
         // Make keyguard locked and set the top activity show-when-locked.
         KeyguardController keyguardController = activity.mTaskSupervisor.getKeyguardController();
         int displayId = activity.getDisplayId();
-        doReturn(true).when(keyguardController).isKeyguardLocked(eq(displayId));
+        keyguardController.setKeyguardShown(displayId, true /* keyguardShowing */,
+                false /* aodShowing */);
         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
         topActivity.setVisibleRequested(true);
         topActivity.nowVisible = true;
@@ -1553,7 +1554,7 @@
 
         // Verify the stack-top activity is occluded keyguard.
         assertEquals(topActivity, task.topRunningActivity());
-        assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
+        assertTrue(keyguardController.isKeyguardOccluded(displayId));
 
         // Finish the top activity
         topActivity.setState(PAUSED, "true");
@@ -1562,7 +1563,7 @@
 
         // Verify new top activity does not occlude keyguard.
         assertEquals(activity, task.topRunningActivity());
-        assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
+        assertFalse(keyguardController.isKeyguardOccluded(displayId));
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index bcb0c6b..0989db4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -59,6 +59,7 @@
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 import android.testing.DexmakerShareClassLoaderRule;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
@@ -128,6 +129,8 @@
     private ActivityManagerInternal mAmInternal;
     @Mock
     private LockTaskController mLockTaskController;
+    @Mock
+    private TaskDisplayArea mTaskDisplayArea;
 
     private ActivityStartInterceptor mInterceptor;
     private ActivityInfo mAInfo = new ActivityInfo();
@@ -139,8 +142,8 @@
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
         mService.mAmInternal = mAmInternal;
-        mInterceptor = new ActivityStartInterceptor(
-                mService, mSupervisor, mRootWindowContainer, mContext);
+        mService.mRootWindowContainer = mRootWindowContainer;
+        mInterceptor = new ActivityStartInterceptor(mService, mSupervisor, mContext);
         mInterceptor.setStates(TEST_USER_ID, TEST_REAL_CALLING_PID, TEST_REAL_CALLING_UID,
                 TEST_START_FLAGS, TEST_CALLING_PACKAGE, null);
 
@@ -201,7 +204,7 @@
                 .thenReturn(PLATFORM_PACKAGE_NAME);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the admin support intent
         assertEquals(ADMIN_SUPPORT_INTENT, mInterceptor.mIntent);
@@ -212,7 +215,7 @@
         final String suspendingPackage = "com.test.suspending.package";
         final SuspendDialogInfo dialogInfo = suspendPackage(suspendingPackage);
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // Check intent parameters
         assertEquals(dialogInfo,
@@ -243,7 +246,7 @@
                 TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT))
                 .thenReturn(false);
 
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         assertTrue(BlockedAppActivity.createIntent(TEST_USER_ID, TEST_PACKAGE_NAME)
                 .filterEquals(mInterceptor.mIntent));
@@ -257,7 +260,8 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(true);
 
         // THEN calling intercept returns false because package also has to be suspended.
-        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null));
+        assertFalse(
+                mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null, null));
     }
 
     @Test
@@ -268,7 +272,7 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(false);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null,  null, 0, 0, null, null));
 
         // THEN the returned intent is the quiet mode intent
         assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -284,7 +288,7 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(true);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the quiet mode intent
         assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -300,7 +304,7 @@
         when(mDevicePolicyManager.isKeepProfilesRunningEnabled()).thenReturn(false);
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the quiet mode intent
         assertTrue(UnlaunchableAppActivity.createInQuietModeDialogIntent(TEST_USER_ID)
@@ -313,7 +317,7 @@
         when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is the confirm credentials intent
         assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
@@ -329,7 +333,7 @@
         mAInfo.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is original intent
         assertSame(originalIntent, mInterceptor.mIntent);
@@ -345,7 +349,7 @@
         mAInfo.directBootAware = false;
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is the confirm credentials intent
         assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
@@ -362,7 +366,7 @@
         mAInfo.directBootAware = true;
 
         // THEN calling intercept returns true
-        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // THEN the returned intent is original intent
         assertSame(originalIntent, mInterceptor.mIntent);
@@ -375,7 +379,7 @@
                 .thenReturn("This app is bad");
 
         // THEN calling intercept returns true
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
 
         // THEN the returned intent is the harmful app warning intent
         assertEquals(HarmfulAppWarningActivity.class.getName(),
@@ -383,11 +387,40 @@
     }
 
     @Test
+    public void testHomeIntentInterception() {
+        // GIVEN a primary home intent and a display area that doesn't support it but supports
+        // secondary home activities
+        Intent originalIntent = new Intent(Intent.ACTION_MAIN);
+        originalIntent.addCategory(Intent.CATEGORY_HOME);
+
+        Intent expectedIntent = new Intent(Intent.ACTION_MAIN);
+        expectedIntent.addCategory(Intent.CATEGORY_SECONDARY_HOME);
+        expectedIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        final int secondaryDisplayId = 7;
+        when(mTaskDisplayArea.getDisplayId()).thenReturn(secondaryDisplayId);
+        when(mRootWindowContainer.shouldPlacePrimaryHomeOnDisplay(eq(secondaryDisplayId)))
+                .thenReturn(false);
+        when(mRootWindowContainer.shouldPlaceSecondaryHomeOnDisplayArea(eq(mTaskDisplayArea)))
+                .thenReturn(true);
+        when(mRootWindowContainer.resolveSecondaryHomeActivity(
+                eq(TEST_USER_ID), eq(mTaskDisplayArea)))
+                .thenReturn(Pair.create(null, expectedIntent));
+
+        // THEN calling intercept returns true
+        assertTrue(mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0,
+                null, mTaskDisplayArea));
+
+        // THEN the returned intent is the secondary home intent
+        assertSame(expectedIntent, mInterceptor.mIntent);
+    }
+
+    @Test
     public void testNoInterception() {
         // GIVEN that none of the interception conditions are met
 
         // THEN calling intercept returns false
-        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
     }
 
     public void addMockInterceptorCallback(
@@ -420,7 +453,7 @@
                 new Intent("android.test.foo"),
                 ActivityOptions.makeBasic().setLaunchDisplayId(3));
 
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
         assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
     }
@@ -429,7 +462,7 @@
     public void testInterceptionCallback_singleCallbackReturnsNull() {
         addMockInterceptorCallback(null, null);
 
-        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertFalse(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
     }
 
     @Test
@@ -437,7 +470,7 @@
         addMockInterceptorCallback(null, null);
         addMockInterceptorCallback(new Intent("android.test.second"), null);
 
-        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.second", mInterceptor.mIntent.getAction());
     }
 
@@ -447,7 +480,7 @@
                 new Intent("android.test.foo"),
                 ActivityOptions.makeBasic().setLaunchDisplayId(3), true);
         ActivityInfo aInfo = mAInfo;
-        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
         assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
         assertEquals(aInfo, mInterceptor.mAInfo); // mAInfo should not be resolved
@@ -459,7 +492,7 @@
                 new Intent("android.test.foo"),
                 ActivityOptions.makeBasic().setLaunchDisplayId(3));
         ActivityInfo aInfo = mAInfo;
-        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null));
+        assertTrue(mInterceptor.intercept(null, null, aInfo, null, null, null, 0, 0, null, null));
         assertEquals("android.test.foo", mInterceptor.mIntent.getAction());
         assertEquals(3, mInterceptor.mActivityOptions.getLaunchDisplayId());
         assertNotEquals(aInfo, mInterceptor.mAInfo); // mAInfo should be resolved after intercept
@@ -488,7 +521,7 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         Intent intent = new Intent().setAction(ACTION_START_SANDBOXED_ACTIVITY);
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, times(1)).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
@@ -505,7 +538,7 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         Intent intent = new Intent().setPackage(sandboxPackageNameMock);
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, times(1)).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
@@ -522,7 +555,7 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         Intent intent = new Intent().setComponent(new ComponentName(sandboxPackageNameMock, ""));
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, times(1)).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
@@ -539,23 +572,23 @@
         when(packageManagerMock.getSdkSandboxPackageName()).thenReturn(sandboxPackageNameMock);
 
         // Intent: null
-        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Action: null, Package: null, ComponentName: null
         Intent intent = new Intent();
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Wrong Action
         intent = new Intent().setAction(Intent.ACTION_VIEW);
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Wrong Package
         intent = new Intent().setPackage("Random");
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         // Wrong ComponentName's package
         intent = new Intent().setComponent(new ComponentName("Random", ""));
-        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null);
+        mInterceptor.intercept(intent, null, mAInfo, null, null, null, 0, 0, null, null);
 
         verify(spyCallback, never()).onInterceptActivityLaunch(
                 any(ActivityInterceptorCallback.ActivityInterceptorInfo.class));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index cb92cc5..ae87e38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1662,9 +1662,10 @@
 
     @Test
     public void testResultCanceledWhenNotAllowedStartingActivity() {
+        final Task task = new TaskBuilder(mSupervisor).build();
         final ActivityStarter starter = prepareStarter(0, false);
         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
-        final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).build();
+        final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setTask(task).build();
         targetRecord.resultTo = sourceRecord;
 
         // Abort the activity start and ensure the sourceRecord gets the result (RESULT_CANCELED).
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index d169a58..5341588 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -24,7 +24,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.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_FIRST_ORDERED_ID;
 import static com.android.server.wm.ActivityInterceptorCallback.SYSTEM_FIRST_ORDERED_ID;
@@ -41,11 +40,9 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -60,7 +57,6 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Binder;
-import android.os.IBinder;
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
@@ -76,7 +72,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
-import org.mockito.MockitoSession;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -304,18 +299,11 @@
      */
     @Test
     public void testEnterPipModeWhenRecordParentChangesToNull() {
-        MockitoSession mockSession = mockitoSession()
-                .initMocks(this)
-                .mockStatic(ActivityRecord.class)
-                .startMocking();
-
-        ActivityRecord record = mock(ActivityRecord.class);
-        IBinder token = mock(IBinder.class);
+        final ActivityRecord record = new ActivityBuilder(mAtm).setCreateTask(true).build();
         PictureInPictureParams params = mock(PictureInPictureParams.class);
         record.pictureInPictureArgs = params;
 
         //mock operations in private method ensureValidPictureInPictureActivityParamsLocked()
-        when(ActivityRecord.forTokenLocked(token)).thenReturn(record);
         doReturn(true).when(record).supportsPictureInPicture();
         doReturn(false).when(params).hasSetAspectRatio();
 
@@ -323,15 +311,13 @@
         doReturn(true).when(record)
                 .checkEnterPictureInPictureState("enterPictureInPictureMode", false);
         doReturn(false).when(record).inPinnedWindowingMode();
-        doReturn(false).when(mAtm).isKeyguardLocked(anyInt());
+        doReturn(false).when(record).isKeyguardLocked();
 
         //to simulate NPE
         doReturn(null).when(record).getParent();
 
-        mAtm.mActivityClientController.enterPictureInPictureMode(token, params);
+        mAtm.mActivityClientController.enterPictureInPictureMode(record.token, params);
         //if record's null parent is not handled gracefully, test will fail with NPE
-
-        mockSession.finishMocking();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
index 4473a31..c84fe08 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecordingControllerTests.java
@@ -123,7 +123,7 @@
         controller.setContentRecordingSessionLocked(mWaitingDisplaySession, mWm);
         verify(mVirtualDisplayContent, atLeastOnce()).setContentRecordingSession(
                 mWaitingDisplaySession);
-        verify(mVirtualDisplayContent).updateRecording();
+        verify(mVirtualDisplayContent, atLeastOnce()).updateRecording();
 
         // WHEN updating the session on the same display, so no longer waiting to record.
         ContentRecordingSession sessionUpdate = ContentRecordingSession.createTaskSession(
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index a2b7da3..ae4ebc1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1698,14 +1698,17 @@
         final Task task = app.getTask();
         final ActivityRecord app2 = new ActivityBuilder(mWm.mAtmService).setTask(task).build();
         mDisplayContent.setFixedRotationLaunchingApp(app2, (mDisplayContent.getRotation() + 1) % 4);
-        doReturn(true).when(app).isInTransition();
+        doReturn(true).when(app).inTransitionSelfOrParent();
         // If the task contains a transition, this should be no-op.
         mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
 
         assertTrue(app2.hasFixedRotationTransform());
         assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
 
-        doReturn(false).when(app).isInTransition();
+        // The display should be unlikely to be in transition, but if it happens, the fixed
+        // rotation should proceed to finish because the activity/task level transition is finished.
+        doReturn(true).when(mDisplayContent).inTransition();
+        doReturn(false).when(app).inTransitionSelfOrParent();
         // Although this notifies app instead of app2 that uses the fixed rotation, app2 should
         // still finish the transform because there is no more transition event.
         mDisplayContent.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(app.token);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index dd90e04..bf86563 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
 import static android.view.DisplayCutout.NO_CUTOUT;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.RoundedCorners.NO_ROUNDED_CORNERS;
@@ -427,11 +428,11 @@
     @SetupWindows(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
     @Test
     public void testImeMinimalSourceFrame() {
+        Assume.assumeFalse("Behavior no longer needed with ENABLE_HIDE_IME_CAPTION_BAR",
+                ENABLE_HIDE_IME_CAPTION_BAR);
+
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
-        final DisplayInfo displayInfo = new DisplayInfo();
-        displayInfo.logicalWidth = 1000;
-        displayInfo.logicalHeight = 2000;
-        displayInfo.rotation = ROTATION_0;
+        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
 
         WindowManager.LayoutParams attrs = mNavBarWindow.mAttrs;
         displayPolicy.addWindowLw(mNavBarWindow, attrs);
@@ -466,10 +467,6 @@
     @Test
     public void testImeInsetsGivenContentFrame() {
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
-        final DisplayInfo displayInfo = new DisplayInfo();
-        displayInfo.logicalWidth = 1000;
-        displayInfo.logicalHeight = 2000;
-        displayInfo.rotation = ROTATION_0;
 
         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
         mImeWindow.getControllableInsetProvider().setServerVisible(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index c4302db..915b387 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -583,6 +583,7 @@
 
         enableOrientationSensor();
 
+        clearInvocations(sMockWm);
         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
         assertTrue(waitForUiHandler());
 
@@ -627,6 +628,7 @@
         when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced(
                 Surface.ROTATION_90)).thenReturn(false);
 
+        clearInvocations(sMockWm);
         // And then ActivityRecord.setRequestedOrientation calls onSetRequestedOrientation.
         mTarget.onSetRequestedOrientation();
 
@@ -864,6 +866,7 @@
         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
+        clearInvocations(sMockWm);
         // ... until half-fold
         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
@@ -899,6 +902,7 @@
         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
 
+        clearInvocations(sMockWm);
         // ... half-fold -> still no rotation
         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
         assertTrue(waitForUiHandler());
@@ -1194,12 +1198,12 @@
     }
 
     @Test
-    public void testIsFixedToUserRotation_displayContentOrientationFixed() throws Exception {
+    public void testIsFixedToUserRotation_displayShouldNotRotateWithContent() throws Exception {
         mBuilder.build();
-        when(mMockDisplayContent.isDisplayOrientationFixed()).thenReturn(true);
+        when(mMockDisplayContent.shouldRotateWithContent()).thenReturn(false);
 
         assertFalse("Display rotation should respect app requested orientation if"
-                + " the display has fixed orientation.", mTarget.isFixedToUserRotation());
+                + " the display does not rotate with content.", mTarget.isFixedToUserRotation());
     }
 
     @Test
@@ -1453,6 +1457,7 @@
                     .thenReturn(mock(TaskDisplayArea.class));
             when(mMockDisplayContent.getWindowConfiguration())
                     .thenReturn(new WindowConfiguration());
+            when(mMockDisplayContent.shouldRotateWithContent()).thenReturn(true);
 
             Field field = DisplayContent.class
                     .getDeclaredField("mFixedRotationTransitionListener");
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 5dfb901..30a8941 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -44,7 +44,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -106,7 +105,6 @@
         assertEquals(uidAmount, mDwpc.mRunningUids.size());
         assertTrue(mDwpc.mRunningUids.contains(TEST_USER_0_ID) == expectedUid0);
         assertTrue(mDwpc.mRunningUids.contains(TEST_USER_1_ID) == expectedUid1);
-
     }
 
     private ActivityRecord launchActivityOnDisplay(DisplayContent display, int uid) {
@@ -197,6 +195,11 @@
 
     @Test
     public void testCanActivityBeLaunched_requiredDisplayCategory() {
+        doReturn(null).when(mWm.mDisplayManagerInternal)
+                .getDisplayWindowPolicyController(anyInt());
+        mSecondaryDisplay = createNewDisplay();
+        assertFalse(mSecondaryDisplay.mDwpcHelper.hasController());
+
         ActivityStarter starter = new ActivityStarter(mock(ActivityStartController.class), mAtm,
                 mSupervisor, mock(ActivityStartInterceptor.class));
         final Task task = new TaskBuilder(mSupervisor).setDisplay(mSecondaryDisplay).build();
@@ -233,20 +236,14 @@
         public boolean canActivityBeLaunched(@NonNull ActivityInfo activity, Intent intent,
                 @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
                 boolean isNewTask) {
-            return false;
+            return canContainActivity(activity, windowingMode, launchingFromDisplayId, isNewTask);
         }
 
         @Override
-        public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
-                @WindowConfiguration.WindowingMode int windowingMode) {
-            final int activityCount = activities.size();
-            for (int i = 0; i < activityCount; i++) {
-                final ActivityInfo aInfo = activities.get(i);
-                if (aInfo.getComponentName().equals(DISALLOWED_ACTIVITY)) {
-                    return false;
-                }
-            }
-            return true;
+        protected boolean canContainActivity(@NonNull ActivityInfo activity,
+                @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+                boolean isNewTask) {
+            return !activity.getComponentName().equals(DISALLOWED_ACTIVITY);
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
index c3db241..4165911 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java
@@ -26,7 +26,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -35,9 +34,14 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
+import static java.util.Objects.requireNonNull;
+
 import android.app.ActivityThread;
 import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
+import android.content.ComponentCallbacks;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
@@ -50,6 +54,8 @@
 import android.window.WindowContextInfo;
 import android.window.WindowTokenClient;
 
+import androidx.annotation.NonNull;
+
 import com.android.server.inputmethod.InputMethodDialogWindowContext;
 
 import org.junit.After;
@@ -58,6 +64,9 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 // TODO(b/157888351): Move the test to inputmethod package once we find the way to test the
 //  scenario there.
 /**
@@ -138,44 +147,96 @@
     @Test
     public void testGetSettingsContextOnDualDisplayContent() {
         final Context context = mWindowContext.get(mSecondaryDisplay.getDisplayId());
+        final MaxBoundsVerifier maxBoundsVerifier = new MaxBoundsVerifier();
+        context.registerComponentCallbacks(maxBoundsVerifier);
+
         final WindowTokenClient tokenClient = (WindowTokenClient) context.getWindowContextToken();
-        assertNotNull(tokenClient);
-        spyOn(tokenClient);
+        spyOn(requireNonNull(tokenClient));
 
         final DisplayArea.Tokens imeContainer = mSecondaryDisplay.getImeContainer();
         spyOn(imeContainer);
         assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay);
 
-        mSecondaryDisplay.mFirstRoot.placeImeContainer(imeContainer);
+        final DisplayAreaGroup firstDaGroup = mSecondaryDisplay.mFirstRoot;
+        maxBoundsVerifier.setMaxBounds(firstDaGroup.getMaxBounds());
+
+        firstDaGroup.placeImeContainer(imeContainer);
 
         verify(imeContainer, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
-                eq(mSecondaryDisplay.mFirstRoot.getConfiguration()));
+                eq(firstDaGroup.getConfiguration()));
         verify(tokenClient, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
-                eq(mSecondaryDisplay.mFirstRoot.getConfiguration()),
+                eq(firstDaGroup.getConfiguration()),
                 eq(mSecondaryDisplay.mDisplayId));
-        assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mFirstRoot);
+        assertThat(imeContainer.getRootDisplayArea()).isEqualTo(firstDaGroup);
+        maxBoundsVerifier.waitAndAssertMaxMetricsMatches();
         assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay);
 
         // Clear the previous invocation histories in case we may count the previous
         // onConfigurationChanged invocation into the next verification.
         clearInvocations(tokenClient, imeContainer);
-        mSecondaryDisplay.mSecondRoot.placeImeContainer(imeContainer);
+        final DisplayAreaGroup secondDaGroup = mSecondaryDisplay.mSecondRoot;
+        maxBoundsVerifier.setMaxBounds(secondDaGroup.getMaxBounds());
+
+        secondDaGroup.placeImeContainer(imeContainer);
 
         verify(imeContainer, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
-                eq(mSecondaryDisplay.mSecondRoot.getConfiguration()));
+                eq(secondDaGroup.getConfiguration()));
         verify(tokenClient, timeout(WAIT_TIMEOUT_MS)).onConfigurationChanged(
-                eq(mSecondaryDisplay.mSecondRoot.getConfiguration()),
+                eq(secondDaGroup.getConfiguration()),
                 eq(mSecondaryDisplay.mDisplayId));
-        assertThat(imeContainer.getRootDisplayArea()).isEqualTo(mSecondaryDisplay.mSecondRoot);
+        assertThat(imeContainer.getRootDisplayArea()).isEqualTo(secondDaGroup);
+        maxBoundsVerifier.waitAndAssertMaxMetricsMatches();
         assertImeSwitchContextMetricsValidity(context, mSecondaryDisplay);
     }
 
     private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) {
         assertThat(context.getDisplayId()).isEqualTo(dc.getDisplayId());
 
+        final Rect imeContainerBounds = dc.getImeContainer().getBounds();
         final Rect contextBounds = context.getSystemService(WindowManager.class)
                 .getMaximumWindowMetrics().getBounds();
-        final Rect imeContainerBounds = dc.getImeContainer().getBounds();
         assertThat(contextBounds).isEqualTo(imeContainerBounds);
     }
+
+    private static final class MaxBoundsVerifier implements ComponentCallbacks {
+
+        private CountDownLatch mLatch;
+
+        private Rect mMaxBounds;
+
+        /**
+         * Sets max bounds to verify whether it matches the
+         * {@link WindowConfiguration#getMaxBounds()} reported from
+         * {@link #onConfigurationChanged(Configuration)} callback, and also resets the count down
+         * latch.
+         *
+         * @param maxBounds max bounds to verify
+         */
+        private void setMaxBounds(@NonNull Rect maxBounds) {
+            mMaxBounds = maxBounds;
+            mLatch = new CountDownLatch(1);
+        }
+
+        /**
+         * Waits for the {@link #onConfigurationChanged(Configuration)} callback whose the reported
+         * {@link WindowConfiguration#getMaxBounds()} matches {@link #mMaxBounds}.
+         */
+        private void waitAndAssertMaxMetricsMatches() {
+            try {
+                assertThat(mLatch.await(WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Test failed because of " + e);
+            }
+        }
+
+        @Override
+        public void onConfigurationChanged(@NonNull Configuration newConfig) {
+            if (newConfig.windowConfiguration.getMaxBounds().equals(mMaxBounds)) {
+                mLatch.countDown();
+            }
+        }
+
+        @Override
+        public void onLowMemory() {}
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
index 06033c7..3fcec96 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
@@ -184,7 +184,7 @@
                 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
         firstPersister.setLetterboxPositionForVerticalReachability(false,
                 LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
-        waitForCompletion(mPersisterQueue);
+        waitForCompletion(firstPersisterQueue);
         final int newPositionForHorizontalReachability =
                 firstPersister.getLetterboxPositionForHorizontalReachability(false);
         final int newPositionForVerticalReachability =
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
index e1fc0cf..80e169d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationTest.java
@@ -250,4 +250,42 @@
                 times(expectedTime)).setLetterboxPositionForVerticalReachability(halfFoldPose,
                 expected);
     }
+
+    @Test
+    public void test_letterboxPositionWhenReachabilityEnabledIsReset() {
+        // Check that horizontal reachability is set with correct arguments
+        mLetterboxConfiguration.resetPersistentLetterboxPositionForHorizontalReachability();
+        verify(mLetterboxConfigurationPersister).setLetterboxPositionForHorizontalReachability(
+                false /* forBookMode */,
+                LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER);
+        verify(mLetterboxConfigurationPersister).setLetterboxPositionForHorizontalReachability(
+                true /* forBookMode */,
+                LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
+
+        // Check that vertical reachability is set with correct arguments
+        mLetterboxConfiguration.resetPersistentLetterboxPositionForVerticalReachability();
+        verify(mLetterboxConfigurationPersister).setLetterboxPositionForVerticalReachability(
+                false /* forTabletopMode */,
+                LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER);
+        verify(mLetterboxConfigurationPersister).setLetterboxPositionForVerticalReachability(
+                true /* forTabletopMode */,
+                LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
+    }
+
+    @Test
+    public void test_lettterboxPositionWhenReachabilityEnabledIsSet() {
+        // Check that horizontal reachability is set with correct arguments
+        mLetterboxConfiguration.setPersistentLetterboxPositionForHorizontalReachability(
+                false /* forBookMode */, LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
+        verify(mLetterboxConfigurationPersister).setLetterboxPositionForHorizontalReachability(
+                false /* forBookMode */,
+                LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
+
+        // Check that vertical reachability is set with correct arguments
+        mLetterboxConfiguration.setPersistentLetterboxPositionForVerticalReachability(
+                false /* forTabletopMode */, LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
+        verify(mLetterboxConfigurationPersister).setLetterboxPositionForVerticalReachability(
+                false /* forTabletopMode */,
+                LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 739737e..07cfbf0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -678,6 +678,39 @@
                 WINDOWING_MODE_FULLSCREEN);
     }
 
+    @Test
+    public void testInheritsSourceTaskWindowingModeWhenActivityIsInDifferentWindowingMode() {
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FULLSCREEN);
+        final ActivityRecord source = createSourceActivity(fullscreenDisplay);
+        source.setWindowingMode(WINDOWING_MODE_PINNED);
+        source.getTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setSource(source).calculate());
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    @Test
+    public void testDoesNotInheritsSourceTaskWindowingModeWhenActivityIsInFreeformWindowingMode() {
+        // The activity could end up in different windowing mode state after calling finish()
+        // while the task would still hold the WINDOWING_MODE_PINNED state, or in other words
+        // be still in the Picture in Picture mode.
+        final TestDisplayContent fullscreenDisplay = createNewDisplayContent(
+                WINDOWING_MODE_FULLSCREEN);
+        final ActivityRecord source = createSourceActivity(fullscreenDisplay);
+        source.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        source.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
+
+        assertEquals(RESULT_CONTINUE,
+                new CalculateRequestBuilder().setSource(source).calculate());
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
 
     @Test
     public void testKeepsPictureInPictureLaunchModeInOptions() {
diff --git a/startop/apps/ColorChanging/app/build.gradle b/startop/apps/ColorChanging/app/build.gradle
index ab955aa..11b14c0 100644
--- a/startop/apps/ColorChanging/app/build.gradle
+++ b/startop/apps/ColorChanging/app/build.gradle
@@ -14,7 +14,7 @@
     buildTypes {
         release {
             minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
         }
     }
 }
diff --git a/startop/apps/ColorChanging/app/proguard-rules.pro b/startop/apps/ColorChanging/app/proguard-rules.pro
deleted file mode 100644
index f1b4245..0000000
--- a/startop/apps/ColorChanging/app/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-#   http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-#   public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index e51696e..7d9b379 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -31,6 +32,7 @@
 import android.os.ParcelFileDescriptor;
 
 import com.android.internal.telecom.IVideoProvider;
+import com.android.server.telecom.flags.Flags;
 
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -720,6 +722,7 @@
          * The underlying connection was added as a transactional call via the
          * {@link TelecomManager#addCall} API.
          */
+        @FlaggedApi(Flags.FLAG_VOIP_APP_ACTIONS_SUPPORT)
         public static final int PROPERTY_IS_TRANSACTIONAL = 0x00008000;
 
         //******************************************************************************************
diff --git a/telecomm/java/android/telecom/CallEndpoint.java b/telecomm/java/android/telecom/CallEndpoint.java
index ed4bf40..a557caf 100644
--- a/telecomm/java/android/telecom/CallEndpoint.java
+++ b/telecomm/java/android/telecom/CallEndpoint.java
@@ -127,7 +127,7 @@
             return false;
         }
         CallEndpoint endpoint = (CallEndpoint) obj;
-        return getEndpointName().toString().contentEquals(endpoint.getEndpointName())
+        return Objects.equals(getEndpointName(), endpoint.getEndpointName())
                 && getEndpointType() == endpoint.getEndpointType()
                 && getIdentifier().equals(endpoint.getIdentifier());
     }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 13e5ff1..0c8603b3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1999,7 +1999,7 @@
             "lte_plus_threshold_bandwidth_khz_int";
 
     /**
-     * The combined channel bandwidth threshold (non-inclusive) in KHz required to display the
+     * The combined channel bandwidth threshold (inclusive) in KHz required to display the
      * NR advanced (i.e. 5G+) data icon. It is 0 by default, meaning minimum bandwidth check is
      * not enabled. Other factors like bands or frequency can also determine whether the NR
      * advanced data icon is shown or not.
@@ -9456,6 +9456,19 @@
             "carrier_supported_satellite_services_per_provider_bundle";
 
     /**
+     * This config enables modem to scan satellite PLMNs specified as per
+     * {@link #KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE} and attach to same
+     * in case cellular networks are not enabled. This will need specific agreement between
+     * satellite provider and the carrier before enabling this flag.
+     *
+     * The default value is false.
+     *
+     * @hide
+     */
+    public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL =
+            "satellite_attach_supported_bool";
+
+    /**
      * Indicating whether DUN APN should be disabled when the device is roaming. In that case,
      * the default APN (i.e. internet) will be used for tethering.
      *
@@ -9881,9 +9894,15 @@
         sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false);
         sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_CLASS_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_CLASS_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WWAN_CLASS_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WLAN_CLASS_OVERRIDE_STRING, "");
+        sDefaults.putString(KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, "");
         sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING, "");
         sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING, "");
@@ -10465,6 +10484,7 @@
         sDefaults.putPersistableBundle(
                 KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
                 PersistableBundle.EMPTY);
+        sDefaults.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false);
         sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
         sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 69b1d63..234ca91 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2649,10 +2649,6 @@
         return getCurrentPhoneType();
     }
 
-    private int getPhoneTypeFromProperty() {
-        return getPhoneTypeFromProperty(getPhoneId());
-    }
-
     /** {@hide} */
     @UnsupportedAppUsage
     private int getPhoneTypeFromProperty(int phoneId) {
@@ -2662,10 +2658,6 @@
         return getPhoneTypeFromNetworkType(phoneId);
     }
 
-    private int getPhoneTypeFromNetworkType() {
-        return getPhoneTypeFromNetworkType(getPhoneId());
-    }
-
     /** {@hide} */
     private int getPhoneTypeFromNetworkType(int phoneId) {
         // When the system property CURRENT_ACTIVE_PHONE, has not been set,
@@ -11564,16 +11556,6 @@
     }
 
    /**
-    * Set TelephonyProperties.icc_operator_numeric for the default phone.
-    *
-    * @hide
-    */
-    public void setSimOperatorNumeric(String numeric) {
-        int phoneId = getPhoneId();
-        setSimOperatorNumericForPhone(phoneId, numeric);
-    }
-
-   /**
     * Set TelephonyProperties.icc_operator_numeric for the given phone.
     *
     * @hide
@@ -11588,16 +11570,6 @@
     }
 
     /**
-     * Set TelephonyProperties.icc_operator_alpha for the default phone.
-     *
-     * @hide
-     */
-    public void setSimOperatorName(String name) {
-        int phoneId = getPhoneId();
-        setSimOperatorNameForPhone(phoneId, name);
-    }
-
-    /**
      * Set TelephonyProperties.icc_operator_alpha for the given phone.
      *
      * @hide
@@ -11850,17 +11822,6 @@
     }
 
     /**
-     * Set baseband version for the default phone.
-     *
-     * @param version baseband version
-     * @hide
-     */
-    public void setBasebandVersion(String version) {
-        int phoneId = getPhoneId();
-        setBasebandVersionForPhone(phoneId, version);
-    }
-
-    /**
      * Set baseband version by phone id.
      *
      * @param phoneId for which baseband version is set
@@ -11898,18 +11859,6 @@
     }
 
     /**
-     * Set phone type for the default phone.
-     *
-     * @param type phone type
-     *
-     * @hide
-     */
-    public void setPhoneType(int type) {
-        int phoneId = getPhoneId();
-        setPhoneType(phoneId, type);
-    }
-
-    /**
      * Set phone type by phone id.
      *
      * @param phoneId for which phone type is set
@@ -11927,19 +11876,6 @@
     }
 
     /**
-     * Get OTASP number schema for the default phone.
-     *
-     * @param defaultValue default value
-     * @return OTA SP number schema
-     *
-     * @hide
-     */
-    public String getOtaSpNumberSchema(String defaultValue) {
-        int phoneId = getPhoneId();
-        return getOtaSpNumberSchemaForPhone(phoneId, defaultValue);
-    }
-
-    /**
      * Get OTASP number schema by phone id.
      *
      * @param phoneId for which OTA SP number schema is get
@@ -11959,19 +11895,6 @@
     }
 
     /**
-     * Get SMS receive capable from system property for the default phone.
-     *
-     * @param defaultValue default value
-     * @return SMS receive capable
-     *
-     * @hide
-     */
-    public boolean getSmsReceiveCapable(boolean defaultValue) {
-        int phoneId = getPhoneId();
-        return getSmsReceiveCapableForPhone(phoneId, defaultValue);
-    }
-
-    /**
      * Get SMS receive capable from system property by phone id.
      *
      * @param phoneId for which SMS receive capable is get
@@ -11989,19 +11912,6 @@
     }
 
     /**
-     * Get SMS send capable from system property for the default phone.
-     *
-     * @param defaultValue default value
-     * @return SMS send capable
-     *
-     * @hide
-     */
-    public boolean getSmsSendCapable(boolean defaultValue) {
-        int phoneId = getPhoneId();
-        return getSmsSendCapableForPhone(phoneId, defaultValue);
-    }
-
-    /**
      * Get SMS send capable from system property by phone id.
      *
      * @param phoneId for which SMS send capable is get
@@ -12065,16 +11975,6 @@
 
     /**
      * Set the alphabetic name of current registered operator.
-     * @param name the alphabetic name of current registered operator.
-     * @hide
-     */
-    public void setNetworkOperatorName(String name) {
-        int phoneId = getPhoneId();
-        setNetworkOperatorNameForPhone(phoneId, name);
-    }
-
-    /**
-     * Set the alphabetic name of current registered operator.
      * @param phoneId which phone you want to set
      * @param name the alphabetic name of current registered operator.
      * @hide
@@ -12108,16 +12008,6 @@
 
     /**
      * Set the numeric name (MCC+MNC) of current registered operator.
-     * @param operator the numeric name (MCC+MNC) of current registered operator
-     * @hide
-     */
-    public void setNetworkOperatorNumeric(String numeric) {
-        int phoneId = getPhoneId();
-        setNetworkOperatorNumericForPhone(phoneId, numeric);
-    }
-
-    /**
-     * Set the numeric name (MCC+MNC) of current registered operator.
      * @param phoneId for which phone type is set
      * @param operator the numeric name (MCC+MNC) of current registered operator
      * @hide
@@ -12133,16 +12023,6 @@
 
     /**
      * Set roaming state of the current network, for GSM purposes.
-     * @param isRoaming is network in romaing state or not
-     * @hide
-     */
-    public void setNetworkRoaming(boolean isRoaming) {
-        int phoneId = getPhoneId();
-        setNetworkRoamingForPhone(phoneId, isRoaming);
-    }
-
-    /**
-     * Set roaming state of the current network, for GSM purposes.
      * @param phoneId which phone you want to set
      * @param isRoaming is network in romaing state or not
      * @hide
@@ -12321,21 +12201,6 @@
     }
 
     /**
-     * TODO delete after SuW migrates to new API.
-     * @hide
-     */
-    public String getLocaleFromDefaultSim() {
-        try {
-            final ITelephony telephony = getITelephony();
-            if (telephony != null) {
-                return telephony.getSimLocaleForSubscriber(getSubId());
-            }
-        } catch (RemoteException ex) {
-        }
-        return null;
-    }
-
-    /**
      * Exception that may be supplied to the callback provided in {@link #requestModemActivityInfo}.
      * @hide
      */
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 9994002a..5f6c14a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -44,10 +44,14 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.time.Duration;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 /**
  * Manages satellite operations such as provisioning, pointing, messaging, location sharing, etc.
@@ -79,6 +83,23 @@
     @Nullable private final Context mContext;
 
     /**
+     * Create a new SatelliteManager object pinned to the given subscription ID.
+     * This is needed only to handle carrier specific satellite features.
+     * For eg: requestSatelliteAttachEnabledForCarrier and
+     *         requestIsSatelliteAttachEnabledForCarrier
+     *
+     * @return a SatelliteManager that uses the given subId for all satellite activities.
+     * @throws IllegalArgumentException if the subscription is invalid.
+     * @hide
+     */
+    public SatelliteManager createForSubscriptionId(int subId) {
+        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+            throw new IllegalArgumentException("Invalid subscription ID");
+        }
+        return new SatelliteManager(mContext, subId);
+    }
+
+    /**
      * Create an instance of the SatelliteManager.
      *
      * @param context The context the SatelliteManager belongs to.
@@ -101,26 +122,26 @@
     }
 
     /**
-     * Exception from the satellite service containing the {@link SatelliteError} error code.
+     * Exception from the satellite service containing the {@link SatelliteResult} error code.
      */
     public static class SatelliteException extends Exception {
-        @SatelliteError private final int mErrorCode;
+        @SatelliteResult private final int mErrorCode;
 
         /**
          * Create a SatelliteException with a given error code.
          *
-         * @param errorCode The {@link SatelliteError}.
+         * @param errorCode The {@link SatelliteResult}.
          */
-        public SatelliteException(@SatelliteError int errorCode) {
+        public SatelliteException(@SatelliteResult int errorCode) {
             mErrorCode = errorCode;
         }
 
         /**
          * Get the error code returned from the satellite service.
          *
-         * @return The {@link SatelliteError}.
+         * @return The {@link SatelliteResult}.
          */
-        @SatelliteError public int getErrorCode() {
+        @SatelliteResult public int getErrorCode() {
             return mErrorCode;
         }
     }
@@ -185,134 +206,134 @@
     /**
      * The request was successfully processed.
      */
-    public static final int SATELLITE_ERROR_NONE = 0;
+    public static final int SATELLITE_RESULT_SUCCESS = 0;
     /**
      * A generic error which should be used only when other specific errors cannot be used.
      */
-    public static final int SATELLITE_ERROR = 1;
+    public static final int SATELLITE_RESULT_ERROR = 1;
     /**
      * Error received from the satellite server.
      */
-    public static final int SATELLITE_SERVER_ERROR = 2;
+    public static final int SATELLITE_RESULT_SERVER_ERROR = 2;
     /**
      * Error received from the vendor service. This generic error code should be used
      * only when the error cannot be mapped to other specific service error codes.
      */
-    public static final int SATELLITE_SERVICE_ERROR = 3;
+    public static final int SATELLITE_RESULT_SERVICE_ERROR = 3;
     /**
      * Error received from satellite modem. This generic error code should be used only when
      * the error cannot be mapped to other specific modem error codes.
      */
-    public static final int SATELLITE_MODEM_ERROR = 4;
+    public static final int SATELLITE_RESULT_MODEM_ERROR = 4;
     /**
      * Error received from the satellite network. This generic error code should be used only when
      * the error cannot be mapped to other specific network error codes.
      */
-    public static final int SATELLITE_NETWORK_ERROR = 5;
+    public static final int SATELLITE_RESULT_NETWORK_ERROR = 5;
     /**
      * Telephony is not in a valid state to receive requests from clients.
      */
-    public static final int SATELLITE_INVALID_TELEPHONY_STATE = 6;
+    public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6;
     /**
      * Satellite modem is not in a valid state to receive requests from clients.
      */
-    public static final int SATELLITE_INVALID_MODEM_STATE = 7;
+    public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7;
     /**
      * Either vendor service, or modem, or Telephony framework has received a request with
      * invalid arguments from its clients.
      */
-    public static final int SATELLITE_INVALID_ARGUMENTS = 8;
+    public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8;
     /**
      * Telephony framework failed to send a request or receive a response from the vendor service
      * or satellite modem due to internal error.
      */
-    public static final int SATELLITE_REQUEST_FAILED = 9;
+    public static final int SATELLITE_RESULT_REQUEST_FAILED = 9;
     /**
      * Radio did not start or is resetting.
      */
-    public static final int SATELLITE_RADIO_NOT_AVAILABLE = 10;
+    public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10;
     /**
      * The request is not supported by either the satellite modem or the network.
      */
-    public static final int SATELLITE_REQUEST_NOT_SUPPORTED = 11;
+    public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11;
     /**
      * Satellite modem or network has no resources available to handle requests from clients.
      */
-    public static final int SATELLITE_NO_RESOURCES = 12;
+    public static final int SATELLITE_RESULT_NO_RESOURCES = 12;
     /**
      * Satellite service is not provisioned yet.
      */
-    public static final int SATELLITE_SERVICE_NOT_PROVISIONED = 13;
+    public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13;
     /**
      * Satellite service provision is already in progress.
      */
-    public static final int SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14;
+    public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14;
     /**
      * The ongoing request was aborted by either the satellite modem or the network.
      * This error is also returned when framework decides to abort current send request as one
      * of the previous send request failed.
      */
-    public static final int SATELLITE_REQUEST_ABORTED = 15;
+    public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15;
     /**
      * The device/subscriber is barred from accessing the satellite service.
      */
-    public static final int SATELLITE_ACCESS_BARRED = 16;
+    public static final int SATELLITE_RESULT_ACCESS_BARRED = 16;
     /**
      * Satellite modem timeout to receive ACK or response from the satellite network after
      * sending a request to the network.
      */
-    public static final int SATELLITE_NETWORK_TIMEOUT = 17;
+    public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17;
     /**
      * Satellite network is not reachable from the modem.
      */
-    public static final int SATELLITE_NOT_REACHABLE = 18;
+    public static final int SATELLITE_RESULT_NOT_REACHABLE = 18;
     /**
      * The device/subscriber is not authorized to register with the satellite service provider.
      */
-    public static final int SATELLITE_NOT_AUTHORIZED = 19;
+    public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19;
     /**
      * The device does not support satellite.
      */
-    public static final int SATELLITE_NOT_SUPPORTED = 20;
+    public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20;
 
     /**
      * The current request is already in-progress.
      */
-    public static final int SATELLITE_REQUEST_IN_PROGRESS = 21;
+    public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21;
 
     /**
      * Satellite modem is currently busy due to which current request cannot be processed.
      */
-    public static final int SATELLITE_MODEM_BUSY = 22;
+    public static final int SATELLITE_RESULT_MODEM_BUSY = 22;
 
     /** @hide */
-    @IntDef(prefix = {"SATELLITE_"}, value = {
-            SATELLITE_ERROR_NONE,
-            SATELLITE_ERROR,
-            SATELLITE_SERVER_ERROR,
-            SATELLITE_SERVICE_ERROR,
-            SATELLITE_MODEM_ERROR,
-            SATELLITE_NETWORK_ERROR,
-            SATELLITE_INVALID_TELEPHONY_STATE,
-            SATELLITE_INVALID_MODEM_STATE,
-            SATELLITE_INVALID_ARGUMENTS,
-            SATELLITE_REQUEST_FAILED,
-            SATELLITE_RADIO_NOT_AVAILABLE,
-            SATELLITE_REQUEST_NOT_SUPPORTED,
-            SATELLITE_NO_RESOURCES,
-            SATELLITE_SERVICE_NOT_PROVISIONED,
-            SATELLITE_SERVICE_PROVISION_IN_PROGRESS,
-            SATELLITE_REQUEST_ABORTED,
-            SATELLITE_ACCESS_BARRED,
-            SATELLITE_NETWORK_TIMEOUT,
-            SATELLITE_NOT_REACHABLE,
-            SATELLITE_NOT_AUTHORIZED,
-            SATELLITE_NOT_SUPPORTED,
-            SATELLITE_REQUEST_IN_PROGRESS,
-            SATELLITE_MODEM_BUSY
+    @IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
+            SATELLITE_RESULT_SUCCESS,
+            SATELLITE_RESULT_ERROR,
+            SATELLITE_RESULT_SERVER_ERROR,
+            SATELLITE_RESULT_SERVICE_ERROR,
+            SATELLITE_RESULT_MODEM_ERROR,
+            SATELLITE_RESULT_NETWORK_ERROR,
+            SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
+            SATELLITE_RESULT_INVALID_MODEM_STATE,
+            SATELLITE_RESULT_INVALID_ARGUMENTS,
+            SATELLITE_RESULT_REQUEST_FAILED,
+            SATELLITE_RESULT_RADIO_NOT_AVAILABLE,
+            SATELLITE_RESULT_REQUEST_NOT_SUPPORTED,
+            SATELLITE_RESULT_NO_RESOURCES,
+            SATELLITE_RESULT_SERVICE_NOT_PROVISIONED,
+            SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS,
+            SATELLITE_RESULT_REQUEST_ABORTED,
+            SATELLITE_RESULT_ACCESS_BARRED,
+            SATELLITE_RESULT_NETWORK_TIMEOUT,
+            SATELLITE_RESULT_NOT_REACHABLE,
+            SATELLITE_RESULT_NOT_AUTHORIZED,
+            SATELLITE_RESULT_NOT_SUPPORTED,
+            SATELLITE_RESULT_REQUEST_IN_PROGRESS,
+            SATELLITE_RESULT_MODEM_BUSY
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface SatelliteError {}
+    public @interface SatelliteResult {}
 
     /**
      * Unknown Non-Terrestrial radio technology. This generic radio technology should be used
@@ -403,7 +424,7 @@
      *                        {@code false} to disable.
      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -412,7 +433,7 @@
 
     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
 
@@ -446,7 +467,7 @@
      *                 will return a {@code boolean} with value {@code true} if the satellite modem
      *                 is enabled and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -464,7 +485,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_ENABLED)) {
                                 boolean isSatelliteEnabled =
                                         resultData.getBoolean(KEY_SATELLITE_ENABLED);
@@ -473,8 +494,8 @@
                             } else {
                                 loge("KEY_SATELLITE_ENABLED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -501,7 +522,7 @@
      *                 will return a {@code boolean} with value {@code true} if demo mode is enabled
      *                 and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -519,7 +540,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) {
                                 boolean isDemoModeEnabled =
                                         resultData.getBoolean(KEY_DEMO_MODE_ENABLED);
@@ -528,8 +549,8 @@
                             } else {
                                 loge("KEY_DEMO_MODE_ENABLED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -556,7 +577,7 @@
      *                 will return a {@code boolean} with value {@code true} if the satellite
      *                 service is supported on the device and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
@@ -572,7 +593,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) {
                                 boolean isSatelliteSupported =
                                         resultData.getBoolean(KEY_SATELLITE_SUPPORTED);
@@ -581,8 +602,8 @@
                             } else {
                                 loge("KEY_SATELLITE_SUPPORTED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -608,7 +629,7 @@
      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
      *                 will return the {@link SatelliteCapabilities} of the satellite service.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -626,7 +647,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) {
                                 SatelliteCapabilities capabilities =
                                         resultData.getParcelable(KEY_SATELLITE_CAPABILITIES,
@@ -636,8 +657,8 @@
                             } else {
                                 loge("KEY_SATELLITE_CAPABILITIES does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -791,16 +812,37 @@
     public @interface DatagramType {}
 
     /**
+     * Satellite communication restricted by user.
+     * @hide
+     */
+    public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0;
+
+    /**
+     * Satellite communication restricted by geolocation. This can be
+     * triggered based upon geofence input provided by carrier to enable or disable satellite.
+     * @hide
+     */
+    public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1;
+
+    /** @hide */
+    @IntDef(prefix = "SATELLITE_COMMUNICATION_RESTRICTION_REASON_", value = {
+            SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER,
+            SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SatelliteCommunicationRestrictionReason {}
+
+    /**
      * Start receiving satellite transmission updates.
      * This can be called by the pointing UI when the user starts pointing to the satellite.
      * Modem should continue to report the pointing input as the device or satellite moves.
-     * Satellite transmission updates are started only on {@link #SATELLITE_ERROR_NONE}.
+     * Satellite transmission updates are started only on {@link #SATELLITE_RESULT_SUCCESS}.
      * All other results indicate that this operation failed.
      * Once satellite transmission updates begin, position and datagram transfer state updates
      * will be sent through {@link SatelliteTransmissionUpdateCallback}.
      *
      * @param executor The executor on which the callback and error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      * @param callback The callback to notify of satellite transmission updates.
      *
      * @throws SecurityException if the caller doesn't have required permission.
@@ -809,7 +851,7 @@
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
     public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener,
             @NonNull SatelliteTransmissionUpdateCallback callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -866,12 +908,12 @@
      * Stop receiving satellite transmission updates.
      * This can be called by the pointing UI when the user stops pointing to the satellite.
      * Satellite transmission updates are stopped and the callback is unregistered only on
-     * {@link #SATELLITE_ERROR_NONE}. All other results that this operation failed.
+     * {@link #SATELLITE_RESULT_SUCCESS}. All other results that this operation failed.
      *
      * @param callback The callback that was passed to {@link
      * #startSatelliteTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -881,7 +923,7 @@
     public void stopSatelliteTransmissionUpdates(
             @NonNull SatelliteTransmissionUpdateCallback callback,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(callback);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -905,7 +947,7 @@
                 } else {
                     loge("stopSatelliteTransmissionUpdates: No internal callback.");
                     executor.execute(() -> Binder.withCleanCallingIdentity(
-                            () -> resultListener.accept(SATELLITE_INVALID_ARGUMENTS)));
+                            () -> resultListener.accept(SATELLITE_RESULT_INVALID_ARGUMENTS)));
                 }
             } else {
                 throw new IllegalStateException("telephony service is null.");
@@ -927,7 +969,7 @@
      *                           request. Even when the cancellation is signaled, Telephony will
      *                           still trigger the callback to return the result of this request.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -937,7 +979,7 @@
     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
             @Nullable CancellationSignal cancellationSignal,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(token);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -980,7 +1022,7 @@
      *              This should match with the token passed as input in
      *              {@link #provisionSatelliteService(String, byte[], CancellationSignal, Executor,
      *              Consumer)}
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -989,7 +1031,7 @@
 
     public void deprovisionSatelliteService(@NonNull String token,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(token);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -1020,14 +1062,14 @@
      * @param executor The executor on which the callback will be called.
      * @param callback The callback to handle the satellite provision state changed event.
      *
-     * @return The {@link SatelliteError} result of the operation.
+     * @return The {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
-    @SatelliteError public int registerForSatelliteProvisionStateChanged(
+    @SatelliteResult public int registerForSatelliteProvisionStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteProvisionStateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1055,7 +1097,7 @@
             loge("registerForSatelliteProvisionStateChanged() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
-        return SATELLITE_REQUEST_FAILED;
+        return SATELLITE_RESULT_REQUEST_FAILED;
     }
 
     /**
@@ -1102,7 +1144,7 @@
      *                 will return a {@code boolean} with value {@code true} if the device is
      *                 provisioned with a satellite provider and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1120,7 +1162,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
                                 boolean isSatelliteProvisioned =
                                         resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
@@ -1129,8 +1171,8 @@
                             } else {
                                 loge("KEY_SATELLITE_PROVISIONED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -1154,14 +1196,14 @@
      * @param executor The executor on which the callback will be called.
      * @param callback The callback to handle the satellite modem state changed event.
      *
-     * @return The {@link SatelliteError} result of the operation.
+     * @return The {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
-    @SatelliteError public int registerForSatelliteModemStateChanged(
+    @SatelliteResult public int registerForSatelliteModemStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteStateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1186,7 +1228,7 @@
             loge("registerForSatelliteModemStateChanged() RemoteException:" + ex);
             ex.rethrowFromSystemServer();
         }
-        return SATELLITE_REQUEST_FAILED;
+        return SATELLITE_RESULT_REQUEST_FAILED;
     }
 
     /**
@@ -1232,14 +1274,14 @@
      * @param callback The callback to handle incoming datagrams over satellite.
      *                 This callback with be invoked when a new datagram is received from satellite.
      *
-     * @return The {@link SatelliteError} result of the operation.
+     * @return The {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
-    @SatelliteError public int registerForSatelliteDatagram(
+    @SatelliteResult public int registerForSatelliteDatagram(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteDatagramCallback callback) {
         Objects.requireNonNull(executor);
@@ -1280,7 +1322,7 @@
             loge("registerForSatelliteDatagram() RemoteException:" + ex);
             ex.rethrowFromSystemServer();
         }
-        return SATELLITE_REQUEST_FAILED;
+        return SATELLITE_RESULT_REQUEST_FAILED;
     }
 
     /**
@@ -1327,7 +1369,7 @@
      * Consumer)} )}
      *
      * @param executor The executor on which the result listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1335,7 +1377,7 @@
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
     public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
 
@@ -1380,7 +1422,7 @@
      *                                 user activity and the application's ability to determine the
      *                                 best possible UX experience for the user.
      * @param executor The executor on which the result listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1390,7 +1432,7 @@
     public void sendSatelliteDatagram(@DatagramType int datagramType,
             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(datagram);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -1426,7 +1468,7 @@
      *                 communication is allowed for the current location and
      *                 {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1445,7 +1487,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
                                 boolean isSatelliteCommunicationAllowed =
                                         resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
@@ -1454,8 +1496,8 @@
                             } else {
                                 loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -1484,7 +1526,7 @@
      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
      *                 will return the time after which the satellite will be visible.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1502,7 +1544,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
                                 int nextVisibilityDuration =
                                         resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
@@ -1512,8 +1554,8 @@
                             } else {
                                 loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -1559,6 +1601,182 @@
         }
     }
 
+    /**
+     * User request to enable or disable carrier supported satellite plmn scan and attach by modem.
+     * <p>
+     * This API should be called by only settings app to pass down the user input for
+     * enabling/disabling satellite. This user input will be persisted across device reboots.
+     * <p>
+     * Satellite will be enabled only when the following conditions are met:
+     * <ul>
+     * <li>Users want to enable it.</li>
+     * <li>There is no satellite communication restriction, which is added by
+     * {@link #addSatelliteAttachRestrictionForCarrier(int, Executor, Consumer)}</li>
+     * <li>The carrier config {@link
+     * android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
+     * {@code true}.</li>
+     * </ul>
+     *
+     * @param enableSatellite {@code true} to enable the satellite and {@code false} to disable.
+     * @param executor The executor on which the error code listener will be called.
+     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void requestSatelliteAttachEnabledForCarrier(boolean enableSatellite,
+            @NonNull @CallbackExecutor Executor executor,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(resultListener);
+
+        if (enableSatellite) {
+            removeSatelliteAttachRestrictionForCarrier(
+                    SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
+        } else {
+            addSatelliteAttachRestrictionForCarrier(
+                    SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
+        }
+    }
+
+    /**
+     * Request to get whether the carrier supported satellite plmn scan and attach by modem is
+     * enabled by user.
+     *
+     * @param executor The executor on which the callback will be called.
+     * @param callback The callback object to which the result will be delivered.
+     *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
+     *                 will return a {@code boolean} with value {@code true} if the satellite
+     *                 is enabled and {@code false} otherwise.
+     *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
+     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void requestIsSatelliteAttachEnabledForCarrier(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+
+        Set<Integer> restrictionReason = getSatelliteAttachRestrictionReasonsForCarrier();
+        executor.execute(() -> callback.onResult(
+                !restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
+    }
+
+    /**
+     * Add a restriction reason for disallowing carrier supported satellite plmn scan and attach
+     * by modem.
+     *
+     * @param reason Reason for disallowing satellite communication.
+     * @param executor The executor on which the error code listener will be called.
+     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void addSatelliteAttachRestrictionForCarrier(
+            @SatelliteCommunicationRestrictionReason int reason,
+            @NonNull @CallbackExecutor Executor executor,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                () -> resultListener.accept(result)));
+                    }
+                };
+                telephony.addSatelliteAttachRestrictionForCarrier(mSubId, reason, errorCallback);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("addSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Remove a restriction reason for disallowing carrier supported satellite plmn scan and attach
+     * by modem.
+     *
+     * @param reason Reason for disallowing satellite communication.
+     * @param executor The executor on which the error code listener will be called.
+     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    public void removeSatelliteAttachRestrictionForCarrier(
+            @SatelliteCommunicationRestrictionReason int reason,
+            @NonNull @CallbackExecutor Executor executor,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() {
+                    @Override
+                    public void accept(int result) {
+                        executor.execute(() -> Binder.withCleanCallingIdentity(
+                                () -> resultListener.accept(result)));
+                    }
+                };
+                telephony.removeSatelliteAttachRestrictionForCarrier(mSubId, reason, errorCallback);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("removeSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get reasons for disallowing satellite attach, as requested by
+     * {@link #addSatelliteAttachRestrictionForCarrier(int, Executor, Consumer)}
+     *
+     * @return Set of reasons for disallowing satellite communication.
+     *
+     * @throws SecurityException if the caller doesn't have required permission.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+    @SatelliteCommunicationRestrictionReason
+    public @NonNull Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                int[] receivedArray =
+                        telephony.getSatelliteAttachRestrictionReasonsForCarrier(mSubId);
+                if (receivedArray.length == 0) {
+                    logd("received set is empty, create empty set");
+                    return new HashSet<>();
+                } else {
+                    return Arrays.stream(receivedArray).boxed().collect(Collectors.toSet());
+                }
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            loge("getSatelliteAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
+            ex.rethrowFromSystemServer();
+        }
+        return null;
+    }
+
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
                 .getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
index d7d892a..7ac06b0 100644
--- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
@@ -43,7 +43,7 @@
      */
     void onSendDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int sendPendingCount,
-            @SatelliteManager.SatelliteError int errorCode);
+            @SatelliteManager.SatelliteResult int errorCode);
 
     /**
      * Called when satellite datagram receive state changed.
@@ -54,5 +54,5 @@
      */
     void onReceiveDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount,
-            @SatelliteManager.SatelliteError int errorCode);
+            @SatelliteManager.SatelliteResult int errorCode);
 }
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index ea4e2e2..02661de 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -382,4 +382,64 @@
      */
     void requestTimeForNextSatelliteVisibility(in IIntegerConsumer resultCallback,
             in IIntegerConsumer callback);
+
+    /**
+     * Set the non-terrestrial PLMN with lower priority than terrestrial networks.
+     * MCC/MNC broadcast by the non-terrestrial networks may not be included in OPLMNwACT file on
+     * SIM profile. Acquisition of satellite based system is lower priority to terrestrial
+     * networks. UE shall make all attempts to acquire terrestrial service prior to camping on
+     * satellite LTE service.
+     *
+     * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
+     *                this information to determine the relevant carrier.
+     * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+     * @param resultCallback The callback to receive the error code result of the operation.
+     *
+     * Valid error codes returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_ARGUMENTS
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:NO_RESOURCES
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    void setSatellitePlmn(int simSlot, in List<String> plmnList,
+            in IIntegerConsumer resultCallback);
+
+    /**
+     * Enable or disable satellite in the cellular modem associated with a carrier.
+     * Refer setSatellitePlmn for the details of satellite PLMN scanning process.
+     *
+     * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
+     *                this information to determine the relevant carrier.
+     * @param serial Serial number of request.
+     * @param enable {@code true} to enable satellite, {@code false} to disable satellite.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    void setSatelliteEnabledForCarrier(int simSlot, boolean satelliteEnabled,
+         in IIntegerConsumer callback);
+
+    /**
+     * Check whether satellite is enabled in the cellular modem associated with a carrier.
+     *
+     * @param simSlot Indicates the SIM slot to which this API will be applied. The modem will use
+     *                this information to determine the relevant carrier.
+     * @param serial Serial number of request.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    void requestIsSatelliteEnabledForCarrier(int simSlot, in IIntegerConsumer resultCallback,
+            in IBooleanConsumer callback);
 }
diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl
index 5e69215..d687162 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl
@@ -19,7 +19,6 @@
 import android.telephony.satellite.stub.NTRadioTechnology;
 import android.telephony.satellite.stub.PointingInfo;
 import android.telephony.satellite.stub.SatelliteDatagram;
-import android.telephony.satellite.stub.SatelliteError;
 import android.telephony.satellite.stub.SatelliteModemState;
 
 /**
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index 17d026c..6451daf 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -25,6 +25,7 @@
 import com.android.internal.telephony.IIntegerConsumer;
 import com.android.internal.telephony.util.TelephonyUtils;
 
+import java.util.List;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionException;
@@ -212,6 +213,34 @@
                     "requestTimeForNextSatelliteVisibility");
         }
 
+        @Override
+        public void setSatellitePlmn(int simSlot, List<String> plmnList,
+                IIntegerConsumer errorCallback)
+                throws RemoteException {
+            executeMethodAsync(
+                    () -> SatelliteImplBase.this
+                            .setSatellitePlmn(simSlot, plmnList, errorCallback),
+                    "setSatellitePlmn");
+        }
+
+        @Override
+        public void setSatelliteEnabledForCarrier(int simSlot, boolean enableSatellite,
+                IIntegerConsumer errorCallback) throws RemoteException {
+            executeMethodAsync(
+                    () -> SatelliteImplBase.this
+                            .setSatelliteEnabledForCarrier(simSlot, enableSatellite, errorCallback),
+                    "setSatelliteEnabledForCarrier");
+        }
+
+        @Override
+        public void requestIsSatelliteEnabledForCarrier(int simSlot, IIntegerConsumer errorCallback,
+                IBooleanConsumer callback) throws RemoteException {
+            executeMethodAsync(
+                    () -> SatelliteImplBase.this
+                            .requestIsSatelliteEnabledForCarrier(simSlot, errorCallback, callback),
+                    "requestIsSatelliteEnabledForCarrier");
+        }
+
         // Call the methods with a clean calling identity on the executor and wait indefinitely for
         // the future to return.
         private void executeMethodAsync(Runnable r, String errorLogName) throws RemoteException {
@@ -618,4 +647,75 @@
             @NonNull IIntegerConsumer callback) {
         // stub implementation
     }
+
+
+    /**
+     * Set the non-terrestrial PLMN with lower priority than terrestrial networks.
+     * MCC/MNC broadcast by the non-terrestrial networks may not be included in OPLMNwACT file on
+     * SIM profile. Acquisition of satellite based system is lower priority to terrestrial
+     * networks. UE shall make all attempts to acquire terrestrial service prior to camping on
+     * satellite LTE service.
+     * This method must only take effect if {@link #setSatelliteEnabledForCarrier} is {@code true},
+     * and return an error otherwise.
+     *
+     * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
+     * applied. The modem will use this information to determine the relevant carrier.
+     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+     *
+     * Valid error codes returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_ARGUMENTS
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:NO_RESOURCES
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    public void setSatellitePlmn(@NonNull int simLogicalSlotIndex, @NonNull List<String> plmnList,
+            @NonNull IIntegerConsumer errorCallback) {
+        // stub implementation
+    }
+
+    /**
+     * Request to enable or disable carrier supported satellite plmn scan and attach by modem.
+     * Refer {@link #setSatellitePlmn} for the details of satellite PLMN scanning process.
+     *
+     * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
+     * applied. The modem will use this information to determine the relevant carrier.
+     * @param satelliteEnabled {@code true} to enable satellite, {@code false} to disable satellite.
+     * @param callback {@code true} to enable satellite, {@code false} to disable satellite.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    public void setSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex,
+            @NonNull boolean satelliteEnabled, @NonNull IIntegerConsumer callback) {
+        // stub implementation
+    }
+
+    /**
+     * Request to get whether the satellite is enabled in the cellular modem associated with a
+     * carrier.
+     *
+     * @param simLogicalSlotIndex Indicates the SIM logical slot index to which this API will be
+     * applied. The modem will use this information to determine the relevant carrier.
+     * @param errorCallback The callback to receive the error code result of the operation.
+     * @param callback {@code true} to satellite enabled, {@code false} to satellite disabled.
+     *
+     * Valid errors returned:
+     *   SatelliteError:NONE
+     *   SatelliteError:INVALID_MODEM_STATE
+     *   SatelliteError:MODEM_ERR
+     *   SatelliteError:RADIO_NOT_AVAILABLE
+     *   SatelliteError:REQUEST_NOT_SUPPORTED
+     */
+    public void requestIsSatelliteEnabledForCarrier(@NonNull int simLogicalSlotIndex,
+            @NonNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback) {
+        // stub implementation
+    }
 }
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteResult.aidl
similarity index 77%
rename from telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
rename to telephony/java/android/telephony/satellite/stub/SatelliteResult.aidl
index 6a110a9..639b483 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteResult.aidl
@@ -20,91 +20,87 @@
  * {@hide}
  */
 @Backing(type="int")
-enum SatelliteError {
+enum SatelliteResult {
     /**
      * The request was successfully processed.
      */
-    ERROR_NONE = 0,
+    SATELLITE_RESULT_SUCCESS = 0,
     /**
      * A generic error which should be used only when other specific errors cannot be used.
      */
-    SATELLITE_ERROR = 1,
+    SATELLITE_RESULT_ERROR = 1,
     /**
      * Error received from the satellite server.
      */
-    SERVER_ERROR = 2,
+    SATELLITE_RESULT_SERVER_ERROR = 2,
     /**
      * Error received from the vendor service. This generic error code should be used
      * only when the error cannot be mapped to other specific service error codes.
      */
-    SERVICE_ERROR = 3,
+    SATELLITE_RESULT_SERVICE_ERROR = 3,
     /**
      * Error received from satellite modem. This generic error code should be used only when
      * the error cannot be mapped to other specific modem error codes.
      */
-    MODEM_ERROR = 4,
+    SATELLITE_RESULT_MODEM_ERROR = 4,
     /**
      * Error received from the satellite network. This generic error code should be used only when
      * the error cannot be mapped to other specific network error codes.
      */
-    NETWORK_ERROR = 5,
-    /**
-     * Telephony is not in a valid state to receive requests from clients.
-     */
-    INVALID_TELEPHONY_STATE = 6,
+    SATELLITE_RESULT_NETWORK_ERROR = 5,
     /**
      * Satellite modem is not in a valid state to receive requests from clients.
      */
-    INVALID_MODEM_STATE = 7,
+    SATELLITE_RESULT_INVALID_MODEM_STATE = 6,
     /**
      * Either vendor service, or modem, or Telephony framework has received a request with
      * invalid arguments from its clients.
      */
-    INVALID_ARGUMENTS = 8,
+    SATELLITE_RESULT_INVALID_ARGUMENTS = 7,
     /**
      * Telephony framework failed to send a request or receive a response from the vendor service
      * or satellite modem due to internal error.
      */
-    REQUEST_FAILED = 9,
+    SATELLITE_RESULT_REQUEST_FAILED = 8,
     /**
      * Radio did not start or is resetting.
      */
-    RADIO_NOT_AVAILABLE = 10,
+    SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 9,
     /**
      * The request is not supported by either the satellite modem or the network.
      */
-    REQUEST_NOT_SUPPORTED = 11,
+    SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 10,
     /**
      * Satellite modem or network has no resources available to handle requests from clients.
      */
-    NO_RESOURCES = 12,
+    SATELLITE_RESULT_NO_RESOURCES = 11,
     /**
      * Satellite service is not provisioned yet.
      */
-    SERVICE_NOT_PROVISIONED = 13,
+    SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 12,
     /**
      * Satellite service provision is already in progress.
      */
-    SERVICE_PROVISION_IN_PROGRESS = 14,
+    SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 13,
     /**
      * The ongoing request was aborted by either the satellite modem or the network.
      */
-    REQUEST_ABORTED = 15,
+    SATELLITE_RESULT_REQUEST_ABORTED = 14,
     /**
      * The device/subscriber is barred from accessing the satellite service.
      */
-    SATELLITE_ACCESS_BARRED = 16,
+    SATELLITE_RESULT_ACCESS_BARRED = 15,
     /**
      * Satellite modem timeout to receive ACK or response from the satellite network after
      * sending a request to the network.
      */
-    NETWORK_TIMEOUT = 17,
+    SATELLITE_RESULT_NETWORK_TIMEOUT = 16,
     /**
      * Satellite network is not reachable from the modem.
      */
-    SATELLITE_NOT_REACHABLE = 18,
+    SATELLITE_RESULT_NOT_REACHABLE = 17,
     /**
      * The device/subscriber is not authorized to register with the satellite service provider.
      */
-    NOT_AUTHORIZED = 19
+    SATELLITE_RESULT_NOT_AUTHORIZED = 18
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 06071fe..3aa5a5a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3033,4 +3033,42 @@
      @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
                  + "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)")
      List<String> getShaIdFromAllowList(String pkgName, int carrierId);
+
+    /**
+     * Add a restriction reason for disallowing satellite communication.
+     *
+     * @param subId The subId of the subscription to request for.
+     * @param reason Reason for disallowing satellite communication for carrier.
+     * @param callback Listener for the {@link SatelliteManager.SatelliteError} result of the
+     * operation.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void addSatelliteAttachRestrictionForCarrier(int subId, int reason,
+            in IIntegerConsumer callback);
+
+    /**
+     * Remove a restriction reason for disallowing satellite communication.
+     *
+     * @param subId The subId of the subscription to request for.
+     * @param reason Reason for disallowing satellite communication.
+     * @param callback Listener for the {@link SatelliteManager.SatelliteError} result of the
+     * operation.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    void removeSatelliteAttachRestrictionForCarrier(int subId, int reason,
+            in IIntegerConsumer callback);
+
+    /**
+     * Get reasons for disallowing satellite communication, as requested by
+     * {@link #addSatelliteAttachRestrictionForCarrier(int, int)}.
+     *
+     * @param subId The subId of the subscription to request for.
+     *
+     * @return Set of reasons for disallowing satellite communication.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+            + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+    int[] getSatelliteAttachRestrictionReasonsForCarrier(int subId);
 }
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/AndroidManifest.xml b/tests/ApkVerityTest/ApkVerityTestApp/feature_split/AndroidManifest.xml
deleted file mode 100644
index 3f1a4f3..0000000
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/AndroidManifest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  * 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.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.apkverity"
-    android:isFeatureSplit="true"
-    split="feature_x">
-    <application>
-        <activity android:name=".feature_x.DummyActivity"/>
-    </application>
-</manifest>
diff --git a/tests/ApkVerityTest/TEST_MAPPING b/tests/ApkVerityTest/TEST_MAPPING
deleted file mode 100644
index 72d9614..0000000
--- a/tests/ApkVerityTest/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "ApkVerityTest"
-    },
-    // nextgen test only runs during postsubmit.
-    {
-      "name": "ApkVerityTest",
-      "keywords": ["nextgen"]
-    }
-  ]
-}
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java b/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
deleted file mode 100644
index 482f633..0000000
--- a/tests/ApkVerityTest/src/com/android/apkverity/ApkVerityTest.java
+++ /dev/null
@@ -1,579 +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.apkverity;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.platform.test.annotations.RootPermissionTest;
-
-import com.android.blockdevicewriter.BlockDeviceWriter;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import com.android.tradefed.util.CommandResult;
-import com.android.tradefed.util.CommandStatus;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This test makes sure app installs with fs-verity signature, and on-access verification works.
- *
- * <p>When an app is installed, all or none of the files should have their corresponding .fsv_sig
- * signature file. Otherwise, install will fail.
- *
- * <p>Once installed, file protected by fs-verity is verified by kernel every time a block is loaded
- * from disk to memory. The file is immutable by design, enforced by filesystem.
- *
- * <p>In order to make sure a block of the file is readable only if the underlying block on disk
- * stay intact, the test needs to bypass the filesystem and tampers with the corresponding physical
- * address against the block device.
- *
- * <p>Requirements to run this test:
- * <ul>
- *   <li>Device is rootable</li>
- *   <li>The filesystem supports fs-verity</li>
- *   <li>The feature flag is enabled</li>
- * </ul>
- */
-@RootPermissionTest
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class ApkVerityTest extends BaseHostJUnit4Test {
-    private static final String TARGET_PACKAGE = "com.android.apkverity";
-
-    private static final String BASE_APK = "ApkVerityTestApp.apk";
-    private static final String BASE_APK_DM = "ApkVerityTestApp.dm";
-    private static final String SPLIT_APK = "ApkVerityTestAppSplit.apk";
-    private static final String SPLIT_APK_DM = "ApkVerityTestAppSplit.dm";
-
-    private static final String INSTALLED_BASE_APK = "base.apk";
-    private static final String INSTALLED_BASE_DM = "base.dm";
-    private static final String INSTALLED_SPLIT_APK = "split_feature_x.apk";
-    private static final String INSTALLED_SPLIT_DM = "split_feature_x.dm";
-    private static final String INSTALLED_BASE_APK_FSV_SIG = "base.apk.fsv_sig";
-    private static final String INSTALLED_BASE_DM_FSV_SIG = "base.dm.fsv_sig";
-    private static final String INSTALLED_SPLIT_APK_FSV_SIG = "split_feature_x.apk.fsv_sig";
-    private static final String INSTALLED_SPLIT_DM_FSV_SIG = "split_feature_x.dm.fsv_sig";
-
-    private static final String DAMAGING_EXECUTABLE = "/data/local/tmp/block_device_writer";
-    private static final String CERT_PATH = "/data/local/tmp/ApkVerityTestCert.der";
-
-    /** Only 4K page is supported by fs-verity currently. */
-    private static final int FSVERITY_PAGE_SIZE = 4096;
-
-    private ITestDevice mDevice;
-    private boolean mDmRequireFsVerity;
-
-    @Before
-    public void setUp() throws DeviceNotAvailableException {
-        mDevice = getDevice();
-        mDmRequireFsVerity = "true".equals(
-                mDevice.getProperty("pm.dexopt.dm.require_fsverity"));
-
-        expectRemoteCommandToSucceed("cmd file_integrity append-cert " + CERT_PATH);
-        uninstallPackage(TARGET_PACKAGE);
-    }
-
-    @After
-    public void tearDown() throws DeviceNotAvailableException {
-        expectRemoteCommandToSucceed("cmd file_integrity remove-last-cert");
-        uninstallPackage(TARGET_PACKAGE);
-    }
-
-    @Test
-    public void testFsverityKernelSupports() throws DeviceNotAvailableException {
-        ITestDevice.MountPointInfo mountPoint = mDevice.getMountPointInfo("/data");
-        expectRemoteCommandToSucceed("test -f /sys/fs/" + mountPoint.type + "/features/verity");
-    }
-
-    @Test
-    public void testInstallBase() throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG);
-        verifyInstalledFilesHaveFsverity(INSTALLED_BASE_APK);
-    }
-
-    @Test
-    public void testInstallBaseWithWrongSignature()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFile(BASE_APK)
-                .addFile(SPLIT_APK_DM + ".fsv_sig",
-                        BASE_APK + ".fsv_sig")
-                .runExpectingFailure();
-    }
-
-    @Test
-    public void testInstallBaseWithSplit()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .addFileAndSignature(SPLIT_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG,
-                INSTALLED_SPLIT_APK,
-                INSTALLED_SPLIT_APK_FSV_SIG);
-        verifyInstalledFilesHaveFsverity(
-                INSTALLED_BASE_APK,
-                INSTALLED_SPLIT_APK);
-    }
-
-    @Test
-    public void testInstallBaseWithDm() throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .addFileAndSignature(BASE_APK_DM)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG,
-                INSTALLED_BASE_DM,
-                INSTALLED_BASE_DM_FSV_SIG);
-        verifyInstalledFilesHaveFsverity(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_DM);
-    }
-
-    @Test
-    public void testInstallEverything() throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .addFileAndSignature(BASE_APK_DM)
-                .addFileAndSignature(SPLIT_APK)
-                .addFileAndSignature(SPLIT_APK_DM)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG,
-                INSTALLED_BASE_DM,
-                INSTALLED_BASE_DM_FSV_SIG,
-                INSTALLED_SPLIT_APK,
-                INSTALLED_SPLIT_APK_FSV_SIG,
-                INSTALLED_SPLIT_DM,
-                INSTALLED_SPLIT_DM_FSV_SIG);
-        verifyInstalledFilesHaveFsverity(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_DM,
-                INSTALLED_SPLIT_APK,
-                INSTALLED_SPLIT_DM);
-    }
-
-    @Test
-    public void testInstallSplitOnly()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG);
-
-        new InstallMultiple()
-                .inheritFrom(TARGET_PACKAGE)
-                .addFileAndSignature(SPLIT_APK)
-                .run();
-
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG,
-                INSTALLED_SPLIT_APK,
-                INSTALLED_SPLIT_APK_FSV_SIG);
-        verifyInstalledFilesHaveFsverity(
-                INSTALLED_BASE_APK,
-                INSTALLED_SPLIT_APK);
-    }
-
-    @Test
-    public void testInstallSplitOnlyMissingSignature()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG);
-
-        new InstallMultiple()
-                .inheritFrom(TARGET_PACKAGE)
-                .addFile(SPLIT_APK)
-                .runExpectingFailure();
-    }
-
-    @Test
-    public void testInstallSplitOnlyWithoutBaseSignature()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFile(BASE_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-        verifyInstalledFiles(INSTALLED_BASE_APK);
-
-        new InstallMultiple()
-                .inheritFrom(TARGET_PACKAGE)
-                .addFileAndSignature(SPLIT_APK)
-                .run();
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_SPLIT_APK,
-                INSTALLED_SPLIT_APK_FSV_SIG);
-    }
-
-    @Test
-    public void testInstallOnlyDmHasFsvSig()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFile(BASE_APK)
-                .addFileAndSignature(BASE_APK_DM)
-                .addFile(SPLIT_APK)
-                .addFileAndSignature(SPLIT_APK_DM)
-                .run();
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_DM,
-                INSTALLED_BASE_DM_FSV_SIG,
-                INSTALLED_SPLIT_APK,
-                INSTALLED_SPLIT_DM,
-                INSTALLED_SPLIT_DM_FSV_SIG);
-        verifyInstalledFilesHaveFsverity(
-                INSTALLED_BASE_DM,
-                INSTALLED_SPLIT_DM);
-    }
-
-    @Test
-    public void testInstallDmWithoutFsvSig_Base()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        InstallMultiple installer = new InstallMultiple()
-                .addFile(BASE_APK)
-                .addFile(BASE_APK_DM)
-                .addFile(SPLIT_APK)
-                .addFileAndSignature(SPLIT_APK_DM);
-        if (mDmRequireFsVerity) {
-            installer.runExpectingFailure();
-        } else {
-            installer.run();
-            verifyInstalledFiles(
-                    INSTALLED_BASE_APK,
-                    INSTALLED_BASE_DM,
-                    INSTALLED_SPLIT_APK,
-                    INSTALLED_SPLIT_DM,
-                    INSTALLED_SPLIT_DM_FSV_SIG);
-            verifyInstalledFilesHaveFsverity(INSTALLED_SPLIT_DM);
-        }
-    }
-
-    @Test
-    public void testInstallDmWithoutFsvSig_Split()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        InstallMultiple installer = new InstallMultiple()
-                .addFile(BASE_APK)
-                .addFileAndSignature(BASE_APK_DM)
-                .addFile(SPLIT_APK)
-                .addFile(SPLIT_APK_DM);
-        if (mDmRequireFsVerity) {
-            installer.runExpectingFailure();
-        } else {
-            installer.run();
-            verifyInstalledFiles(
-                    INSTALLED_BASE_APK,
-                    INSTALLED_BASE_DM,
-                    INSTALLED_BASE_DM_FSV_SIG,
-                    INSTALLED_SPLIT_APK,
-                    INSTALLED_SPLIT_DM);
-            verifyInstalledFilesHaveFsverity(INSTALLED_BASE_DM);
-        }
-    }
-
-    @Test
-    public void testInstallSomeApkIsMissingFsvSig_Base()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .addFileAndSignature(BASE_APK_DM)
-                .addFile(SPLIT_APK)
-                .addFileAndSignature(SPLIT_APK_DM)
-                .runExpectingFailure();
-    }
-
-    @Test
-    public void testInstallSomeApkIsMissingFsvSig_Split()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFile(BASE_APK)
-                .addFileAndSignature(BASE_APK_DM)
-                .addFileAndSignature(SPLIT_APK)
-                .addFileAndSignature(SPLIT_APK_DM)
-                .runExpectingFailure();
-    }
-
-    @Test
-    public void testInstallBaseWithFsvSigThenSplitWithout()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFileAndSignature(BASE_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-        verifyInstalledFiles(
-                INSTALLED_BASE_APK,
-                INSTALLED_BASE_APK_FSV_SIG);
-
-        new InstallMultiple()
-                .addFile(SPLIT_APK)
-                .runExpectingFailure();
-    }
-
-    @Test
-    public void testInstallBaseWithoutFsvSigThenSplitWith()
-            throws DeviceNotAvailableException, FileNotFoundException {
-        new InstallMultiple()
-                .addFile(BASE_APK)
-                .run();
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-        verifyInstalledFiles(INSTALLED_BASE_APK);
-
-        new InstallMultiple()
-                .addFileAndSignature(SPLIT_APK)
-                .runExpectingFailure();
-    }
-
-    @Test
-    public void testFsverityFileIsImmutableAndReadable() throws DeviceNotAvailableException {
-        new InstallMultiple().addFileAndSignature(BASE_APK).run();
-        String apkPath = getApkPath(TARGET_PACKAGE);
-
-        assertNotNull(getDevice().getAppPackageInfo(TARGET_PACKAGE));
-        expectRemoteCommandToFail("echo -n '' >> " + apkPath);
-        expectRemoteCommandToSucceed("cat " + apkPath + " > /dev/null");
-    }
-
-    @Test
-    public void testFsverityFailToReadModifiedBlockAtFront() throws DeviceNotAvailableException {
-        new InstallMultiple().addFileAndSignature(BASE_APK).run();
-        String apkPath = getApkPath(TARGET_PACKAGE);
-
-        long apkSize = getFileSizeInBytes(apkPath);
-        long offsetFirstByte = 0;
-
-        // The first two pages should be both readable at first.
-        assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetFirstByte));
-        if (apkSize > offsetFirstByte + FSVERITY_PAGE_SIZE) {
-            assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath,
-                    offsetFirstByte + FSVERITY_PAGE_SIZE));
-        }
-
-        // Damage the file directly against the block device.
-        damageFileAgainstBlockDevice(apkPath, offsetFirstByte);
-
-        // Expect actual read from disk to fail but only at damaged page.
-        expectReadFromBlockDeviceToFail(apkPath, offsetFirstByte);
-        if (apkSize > offsetFirstByte + FSVERITY_PAGE_SIZE) {
-            long lastByteOfTheSamePage =
-                    offsetFirstByte % FSVERITY_PAGE_SIZE + FSVERITY_PAGE_SIZE - 1;
-            assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, lastByteOfTheSamePage));
-            assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, lastByteOfTheSamePage + 1));
-        }
-    }
-
-    @Test
-    public void testFsverityFailToReadModifiedBlockAtBack() throws DeviceNotAvailableException {
-        new InstallMultiple().addFileAndSignature(BASE_APK).run();
-        String apkPath = getApkPath(TARGET_PACKAGE);
-
-        long apkSize = getFileSizeInBytes(apkPath);
-        long offsetOfLastByte = apkSize - 1;
-
-        // The first two pages should be both readable at first.
-        assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, offsetOfLastByte));
-        if (offsetOfLastByte - FSVERITY_PAGE_SIZE > 0) {
-            assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath,
-                    offsetOfLastByte - FSVERITY_PAGE_SIZE));
-        }
-
-        // Damage the file directly against the block device.
-        damageFileAgainstBlockDevice(apkPath, offsetOfLastByte);
-
-        // Expect actual read from disk to fail but only at damaged page.
-        expectReadFromBlockDeviceToFail(apkPath, offsetOfLastByte);
-        if (offsetOfLastByte - FSVERITY_PAGE_SIZE > 0) {
-            long firstByteOfTheSamePage = offsetOfLastByte - offsetOfLastByte % FSVERITY_PAGE_SIZE;
-            assertFalse(BlockDeviceWriter.canReadByte(mDevice, apkPath, firstByteOfTheSamePage));
-            assertTrue(BlockDeviceWriter.canReadByte(mDevice, apkPath, firstByteOfTheSamePage - 1));
-        }
-    }
-
-    private void verifyInstalledFilesHaveFsverity(String... filenames)
-            throws DeviceNotAvailableException {
-        // Verify that all files are protected by fs-verity
-        String apkPath = getApkPath(TARGET_PACKAGE);
-        String appDir = apkPath.substring(0, apkPath.lastIndexOf("/"));
-        long kTargetOffset = 0;
-        for (String basename : filenames) {
-            String path = appDir + "/" + basename;
-            damageFileAgainstBlockDevice(path, kTargetOffset);
-
-            expectReadFromBlockDeviceToFail(path, kTargetOffset);
-        }
-    }
-
-    private void expectReadFromBlockDeviceToFail(String readPath, long offset)
-            throws DeviceNotAvailableException {
-        // Retry is sometimes needed to pass the test. Package manager may have FD leaks
-        // (see b/122744005 as example) that prevents the file in question to be evicted
-        // from filesystem cache. Forcing GC workarounds the problem.
-        int retry = 5;
-        for (; retry > 0; retry--) {
-            BlockDeviceWriter.dropCaches(mDevice);
-            if (!BlockDeviceWriter.canReadByte(mDevice, readPath, offset)) {
-                break;
-            }
-            try {
-                String openFiles = expectRemoteCommandToSucceed("lsof " + readPath);
-                CLog.d("lsof: " + openFiles);
-                Thread.sleep(1000);
-                forceGCOnOpenFilesProcess(getOpenFilesPIDs(openFiles));
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                return;
-            }
-        }
-        assertTrue("Read from " + readPath + " should fail", retry > 0);
-    }
-
-    /**
-     * This is a helper method that parses the lsof output to get PIDs of process holding FD.
-     * Here is an example output of lsof. This method extracts the second columns(PID).
-     *
-     * Example lsof output:
-     *  COMMAND      PID     USER    FD     TYPE   DEVICE   SIZE/OFF  NODE   NAME
-     * .example.app  1063    u0_a38  mem    REG    253,6    8599      12826  example.apk
-     * .example.app  1063    u0_a38  99r    REG    253,6    8599      12826  example.apk
-     */
-    private Set<String> getOpenFilesPIDs(String lsof) {
-        Set<String> openFilesPIDs = new HashSet<>();
-        String[] lines = lsof.split("\n");
-        for (int i = 1; i < lines.length; i++) {
-            openFilesPIDs.add(lines[i].split("\\s+")[1]);
-        }
-        return openFilesPIDs;
-    }
-
-    /**
-     * This is a helper method that forces GC on processes given their PIDs.
-     * That is to execute shell command "kill -10" on PIDs.
-     */
-    private void forceGCOnOpenFilesProcess(Set<String> openFilesPIDs)
-            throws DeviceNotAvailableException {
-        for (String openFilePID : openFilesPIDs) {
-            mDevice.executeShellV2Command("kill -10 " + openFilePID);
-        }
-    }
-
-    private void verifyInstalledFiles(String... filenames) throws DeviceNotAvailableException {
-        String apkPath = getApkPath(TARGET_PACKAGE);
-        String appDir = apkPath.substring(0, apkPath.lastIndexOf("/"));
-        // Exclude directories since we only care about files.
-        HashSet<String> actualFiles = new HashSet<>(Arrays.asList(
-                expectRemoteCommandToSucceed("ls -p " + appDir + " | grep -v '/'").split("\n")));
-
-        HashSet<String> expectedFiles = new HashSet<>(Arrays.asList(filenames));
-        assertEquals(expectedFiles, actualFiles);
-    }
-
-    private void damageFileAgainstBlockDevice(String path, long offsetOfTargetingByte)
-            throws DeviceNotAvailableException {
-        assertTrue(path.startsWith("/data/"));
-        ITestDevice.MountPointInfo mountPoint = mDevice.getMountPointInfo("/data");
-        ArrayList<String> args = new ArrayList<>();
-        args.add(DAMAGING_EXECUTABLE);
-        if ("f2fs".equals(mountPoint.type)) {
-            args.add("--use-f2fs-pinning");
-        }
-        args.add(mountPoint.filesystem);
-        args.add(path);
-        args.add(Long.toString(offsetOfTargetingByte));
-        expectRemoteCommandToSucceed(String.join(" ", args));
-    }
-
-    private String getApkPath(String packageName) throws DeviceNotAvailableException {
-        String line = expectRemoteCommandToSucceed("pm path " + packageName + " | grep base.apk");
-        int index = line.trim().indexOf(":");
-        assertTrue(index >= 0);
-        return line.substring(index + 1);
-    }
-
-    private long getFileSizeInBytes(String packageName) throws DeviceNotAvailableException {
-        return Long.parseLong(expectRemoteCommandToSucceed("stat -c '%s' " + packageName).trim());
-    }
-
-    private String expectRemoteCommandToSucceed(String cmd) throws DeviceNotAvailableException {
-        CommandResult result = mDevice.executeShellV2Command(cmd);
-        assertEquals("`" + cmd + "` failed: " + result.getStderr(), CommandStatus.SUCCESS,
-                result.getStatus());
-        return result.getStdout();
-    }
-
-    private void expectRemoteCommandToFail(String cmd) throws DeviceNotAvailableException {
-        CommandResult result = mDevice.executeShellV2Command(cmd);
-        assertTrue("Unexpected success from `" + cmd + "`: " + result.getStderr(),
-                result.getStatus() != CommandStatus.SUCCESS);
-    }
-
-    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
-        InstallMultiple() {
-            super(getDevice(), getBuild());
-        }
-
-        InstallMultiple addFileAndSignature(String filename) {
-            try {
-                addFile(filename);
-                addFile(filename + ".fsv_sig");
-            } catch (FileNotFoundException e) {
-                fail("Missing test file: " + e);
-            }
-            return this;
-        }
-    }
-}
diff --git a/tests/ApkVerityTest/src/com/android/apkverity/BaseInstallMultiple.java b/tests/ApkVerityTest/src/com/android/apkverity/BaseInstallMultiple.java
deleted file mode 100644
index 02e73d1..0000000
--- a/tests/ApkVerityTest/src/com/android/apkverity/BaseInstallMultiple.java
+++ /dev/null
@@ -1,140 +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.apkverity;
-
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
- *
- * <code> private class InstallMultiple extends BaseInstallMultiple&lt;InstallMultiple&gt; { public
- * InstallMultiple() { super(getDevice(), null); } } </code>
- */
-/*package*/ class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
-
-    private final ITestDevice mDevice;
-    private final IBuildInfo mBuild;
-
-    private final List<String> mArgs = new ArrayList<>();
-    private final Map<File, String> mFileToRemoteMap = new HashMap<>();
-
-    /*package*/ BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo) {
-        mDevice = device;
-        mBuild = buildInfo;
-        addArg("-g");
-    }
-
-    T addArg(String arg) {
-        mArgs.add(arg);
-        return (T) this;
-    }
-
-    T addFile(String filename) throws FileNotFoundException {
-        return addFile(filename, filename);
-    }
-
-    T addFile(String filename, String remoteName) throws FileNotFoundException {
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
-        mFileToRemoteMap.put(buildHelper.getTestFile(filename), remoteName);
-        return (T) this;
-    }
-
-    T inheritFrom(String packageName) {
-        addArg("-r");
-        addArg("-p " + packageName);
-        return (T) this;
-    }
-
-    void run() throws DeviceNotAvailableException {
-        run(true);
-    }
-
-    void runExpectingFailure() throws DeviceNotAvailableException {
-        run(false);
-    }
-
-    private void run(boolean expectingSuccess) throws DeviceNotAvailableException {
-        final ITestDevice device = mDevice;
-
-        // Create an install session
-        final StringBuilder cmd = new StringBuilder();
-        cmd.append("pm install-create");
-        for (String arg : mArgs) {
-            cmd.append(' ').append(arg);
-        }
-
-        String result = device.executeShellCommand(cmd.toString());
-        TestCase.assertTrue(result, result.startsWith("Success"));
-
-        final int start = result.lastIndexOf("[");
-        final int end = result.lastIndexOf("]");
-        int sessionId = -1;
-        try {
-            if (start != -1 && end != -1 && start < end) {
-                sessionId = Integer.parseInt(result.substring(start + 1, end));
-            }
-        } catch (NumberFormatException e) {
-            throw new IllegalStateException("Failed to parse install session: " + result);
-        }
-        if (sessionId == -1) {
-            throw new IllegalStateException("Failed to create install session: " + result);
-        }
-
-        // Push our files into session. Ideally we'd use stdin streaming,
-        // but ddmlib doesn't support it yet.
-        for (final Map.Entry<File, String> entry : mFileToRemoteMap.entrySet()) {
-            final File file = entry.getKey();
-            final String remoteName  = entry.getValue();
-            final String remotePath = "/data/local/tmp/" + file.getName();
-            if (!device.pushFile(file, remotePath)) {
-                throw new IllegalStateException("Failed to push " + file);
-            }
-
-            cmd.setLength(0);
-            cmd.append("pm install-write");
-            cmd.append(' ').append(sessionId);
-            cmd.append(' ').append(remoteName);
-            cmd.append(' ').append(remotePath);
-
-            result = device.executeShellCommand(cmd.toString());
-            TestCase.assertTrue(result, result.startsWith("Success"));
-        }
-
-        // Everything staged; let's pull trigger
-        cmd.setLength(0);
-        cmd.append("pm install-commit");
-        cmd.append(' ').append(sessionId);
-
-        result = device.executeShellCommand(cmd.toString());
-        if (expectingSuccess) {
-            TestCase.assertTrue(result, result.contains("Success"));
-        } else {
-            TestCase.assertFalse(result, result.contains("Success"));
-        }
-    }
-}
diff --git a/tests/ApkVerityTest/testdata/Android.bp b/tests/ApkVerityTest/testdata/Android.bp
deleted file mode 100644
index ccfc4c9..0000000
--- a/tests/ApkVerityTest/testdata/Android.bp
+++ /dev/null
@@ -1,87 +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 {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    //   SPDX-license-identifier-MIT
-    //   SPDX-license-identifier-Unicode-DFS
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
-    name: "ApkVerityTestKeyPem",
-    srcs: ["ApkVerityTestKey.pem"],
-}
-
-filegroup {
-    name: "ApkVerityTestCertPem",
-    srcs: ["ApkVerityTestCert.pem"],
-}
-
-filegroup {
-    name: "ApkVerityTestCertDer",
-    srcs: ["ApkVerityTestCert.der"],
-}
-
-filegroup {
-    name: "ApkVerityTestAppDm",
-    srcs: ["ApkVerityTestApp.dm"],
-}
-
-filegroup {
-    name: "ApkVerityTestAppSplitDm",
-    srcs: ["ApkVerityTestAppSplit.dm"],
-}
-
-genrule_defaults {
-    name: "apk_verity_sig_gen_default",
-    tools: ["fsverity"],
-    tool_files: [":ApkVerityTestKeyPem", ":ApkVerityTestCertPem"],
-    cmd: "$(location fsverity) sign $(in) $(out) " +
-        "--key=$(location :ApkVerityTestKeyPem) " +
-        "--cert=$(location :ApkVerityTestCertPem) " +
-        "> /dev/null",
-}
-
-genrule {
-    name: "ApkVerityTestAppFsvSig",
-    defaults: ["apk_verity_sig_gen_default"],
-    srcs: [":ApkVerityTestApp"],
-    out: ["ApkVerityTestApp.apk.fsv_sig"],
-}
-
-genrule {
-    name: "ApkVerityTestAppDmFsvSig",
-    defaults: ["apk_verity_sig_gen_default"],
-    srcs: [":ApkVerityTestAppDm"],
-    out: ["ApkVerityTestApp.dm.fsv_sig"],
-}
-
-genrule {
-    name: "ApkVerityTestAppSplitFsvSig",
-    defaults: ["apk_verity_sig_gen_default"],
-    srcs: [":ApkVerityTestAppSplit"],
-    out: ["ApkVerityTestAppSplit.apk.fsv_sig"],
-}
-
-genrule {
-    name: "ApkVerityTestAppSplitDmFsvSig",
-    defaults: ["apk_verity_sig_gen_default"],
-    srcs: [":ApkVerityTestAppSplitDm"],
-    out: ["ApkVerityTestAppSplit.dm.fsv_sig"],
-}
diff --git a/tests/ApkVerityTest/testdata/ApkVerityTestApp.dm b/tests/ApkVerityTest/testdata/ApkVerityTestApp.dm
deleted file mode 100644
index e53a861..0000000
--- a/tests/ApkVerityTest/testdata/ApkVerityTestApp.dm
+++ /dev/null
Binary files differ
diff --git a/tests/ApkVerityTest/testdata/ApkVerityTestAppSplit.dm b/tests/ApkVerityTest/testdata/ApkVerityTestAppSplit.dm
deleted file mode 100644
index 75396f1..0000000
--- a/tests/ApkVerityTest/testdata/ApkVerityTestAppSplit.dm
+++ /dev/null
Binary files differ
diff --git a/tests/ApkVerityTest/testdata/README.md b/tests/ApkVerityTest/testdata/README.md
deleted file mode 100644
index 163cb18..0000000
--- a/tests/ApkVerityTest/testdata/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-This test only runs on rooted / debuggable device.
-
-The test tries to install subsets of base.{apk,dm}, split.{apk,dm} and their
-corresponding .fsv_sig files (generated by build rule). If installed, the
-tests also tries to tamper with the file at absolute disk offset to verify
-if fs-verity is effective.
-
-How to generate dex metadata (.dm)
-==================================
-
-  adb shell profman --generate-test-profile=/data/local/tmp/primary.prof
-  adb pull /data/local/tmp/primary.prof
-  zip foo.dm primary.prof
diff --git a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
index fe2fe0b..08430f2 100644
--- a/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
+++ b/tests/BatteryStatsPerfTest/src/com/android/internal/os/BatteryUsageStatsPerfTest.java
@@ -159,7 +159,7 @@
 
     private static BatteryUsageStats buildBatteryUsageStats() {
         final BatteryUsageStats.Builder builder =
-                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, false)
+                new BatteryUsageStats.Builder(new String[]{"FOO"}, true, false, 0)
                         .setBatteryCapacity(4000)
                         .setDischargePercentage(20)
                         .setDischargedPowerRange(1000, 2000)
diff --git a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
index bb0d30a..5460e4e87 100644
--- a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
+++ b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
@@ -421,7 +421,7 @@
 
     @Test
     public void testChoreographerAttachedAfterSetFrameRate() {
-        Log.i(TAG, "adyabr: starting testChoreographerAttachedAfterSetFrameRate");
+        Log.i(TAG, "starting testChoreographerAttachedAfterSetFrameRate");
 
         class TransactionGenerator implements SurfaceControl.TransactionCommittedListener {
             private SurfaceControl mSc;
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 2ccc0fa..a2ae56e 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -95,6 +95,7 @@
         "flickertestapplib",
         "flickerlib",
         "flickerlib-helpers",
+        "flickerlib-trace_processor_shell",
         "platform-test-annotations",
         "wm-flicker-common-app-helpers",
         "wm-shell-flicker-utils",
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AndroidTestTemplate.xml
index 44a8245..8780385 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AndroidTestTemplate.xml
@@ -61,7 +61,9 @@
         <option name="shell-timeout" value="6600s"/>
         <option name="test-timeout" value="6600s"/>
         <option name="hidden-api-checks" value="false"/>
+        <!-- TODO(b/288396763): re-enable when PerfettoListener is fixed
         <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
+        -->
         <!-- PerfettoListener related arguments -->
         <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
         <option name="instrumentation-arg"
diff --git a/tests/FlickerTests/manifests/AndroidManifest.xml b/tests/FlickerTests/manifests/AndroidManifest.xml
index 1a34d9e..6bc7cbe 100644
--- a/tests/FlickerTests/manifests/AndroidManifest.xml
+++ b/tests/FlickerTests/manifests/AndroidManifest.xml
@@ -44,8 +44,12 @@
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
     <!-- ActivityOptions.makeCustomTaskAnimation() -->
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
-    <!-- Allow the test to write directly to /sdcard/ -->
-    <application android:requestLegacyExternalStorage="true" android:largeHeap="true">
+    <!-- Allow the test to connect to perfetto trace processor -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
+    <application android:requestLegacyExternalStorage="true"
+                 android:networkSecurityConfig="@xml/network_security_config"
+                 android:largeHeap="true">
         <uses-library android:name="android.test.runner"/>
         <uses-library android:name="androidx.window.extensions" android:required="false"/>
 
diff --git a/tests/FlickerTests/res/xml/network_security_config.xml b/tests/FlickerTests/res/xml/network_security_config.xml
new file mode 100644
index 0000000..4bd9ca0
--- /dev/null
+++ b/tests/FlickerTests/res/xml/network_security_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">localhost</domain>
+    </domain-config>
+</network-security-config>
diff --git a/tests/ApkVerityTest/Android.bp b/tests/FsVerityTest/Android.bp
similarity index 79%
rename from tests/ApkVerityTest/Android.bp
rename to tests/FsVerityTest/Android.bp
index f026bea..53606a3 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/FsVerityTest/Android.bp
@@ -22,7 +22,7 @@
 }
 
 java_test_host {
-    name: "ApkVerityTest",
+    name: "FsVerityTest",
     srcs: ["src/**/*.java"],
     libs: [
         "tradefed",
@@ -30,8 +30,10 @@
         "compatibility-host-util",
     ],
     static_libs: [
+        "android.security.flags-aconfig-java-host",
         "block_device_writer_jar",
         "frameworks-base-hostutils",
+        "flag-junit-host",
     ],
     test_suites: [
         "general-tests",
@@ -41,14 +43,6 @@
         "block_device_writer",
     ],
     data: [
-        ":ApkVerityTestCertDer",
-        ":ApkVerityTestApp",
-        ":ApkVerityTestAppFsvSig",
-        ":ApkVerityTestAppDm",
-        ":ApkVerityTestAppDmFsvSig",
-        ":ApkVerityTestAppSplit",
-        ":ApkVerityTestAppSplitFsvSig",
-        ":ApkVerityTestAppSplitDm",
-        ":ApkVerityTestAppSplitDmFsvSig",
+        ":FsVerityTestApp",
     ],
 }
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/FsVerityTest/AndroidTest.xml
similarity index 63%
rename from tests/ApkVerityTest/AndroidTest.xml
rename to tests/FsVerityTest/AndroidTest.xml
index 4487cef..49cbde0 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/FsVerityTest/AndroidTest.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="APK fs-verity integration/regression test">
+<configuration description="fs-verity end-to-end test">
     <option name="test-suite-tag" value="apct" />
 
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
@@ -24,19 +24,9 @@
     <!-- This test requires root to write against block device. -->
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
 
-    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
-        <!-- Disable package verifier prevents it holding the target APK's fd that prevents cache
-             eviction. -->
-        <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
-        <option name="restore-settings" value="true" />
-
-        <!-- Skip in order to prevent reboot that confuses the test flow. -->
-        <option name="force-skip-system-props" value="true" />
-    </target_preparer>
-
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" />
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FsVerityTestApp.apk"/>
+        <option name="cleanup-apks" value="true"/>
     </target_preparer>
 
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
@@ -48,9 +38,7 @@
         <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
     </target_preparer>
 
-    <!-- Skip on HWASan. TODO(b/232288278): Re-enable -->
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
-        <option name="jar" value="ApkVerityTest.jar" />
+        <option name="jar" value="FsVerityTest.jar" />
     </test>
 </configuration>
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp b/tests/FsVerityTest/FsVerityTestApp/Android.bp
similarity index 74%
rename from tests/ApkVerityTest/ApkVerityTestApp/Android.bp
rename to tests/FsVerityTest/FsVerityTestApp/Android.bp
index adf8f9f..43da3ff 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
+++ b/tests/FsVerityTest/FsVerityTestApp/Android.bp
@@ -22,17 +22,8 @@
 }
 
 android_test_helper_app {
-  name: "ApkVerityTestApp",
-  manifest: "AndroidManifest.xml",
-  srcs: ["src/**/*.java"],
-}
-
-android_test_helper_app {
-  name: "ApkVerityTestAppSplit",
-  manifest: "feature_split/AndroidManifest.xml",
-  srcs: ["src/**/*.java"],
-  aaptflags: [
-      "--custom-package com.android.apkverity.feature_x",
-      "--package-id 0x80",
-  ],
+    name: "FsVerityTestApp",
+    manifest: "AndroidManifest.xml",
+    srcs: ["src/**/*.java"],
+    static_libs: ["compatibility-device-util-axt"],
 }
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/AndroidManifest.xml b/tests/FsVerityTest/FsVerityTestApp/AndroidManifest.xml
similarity index 75%
rename from tests/ApkVerityTest/ApkVerityTestApp/AndroidManifest.xml
rename to tests/FsVerityTest/FsVerityTestApp/AndroidManifest.xml
index 0b3ff77..42fe49b 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/AndroidManifest.xml
+++ b/tests/FsVerityTest/FsVerityTestApp/AndroidManifest.xml
@@ -16,8 +16,12 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.apkverity">
+    package="com.android.fsverity">
     <application>
         <activity android:name=".DummyActivity"/>
     </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.fsverity"
+                     android:label="Helper app of fs-verity test">
+    </instrumentation>/>
 </manifest>
diff --git a/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java b/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java
new file mode 100644
index 0000000..2ed4fec
--- /dev/null
+++ b/tests/FsVerityTest/FsVerityTestApp/src/com/android/fsverity/Helper.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fsverity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.Context;
+import android.security.FileIntegrityManager;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Test helper that works with the host-side test to set up a test file, and to verify fs-verity
+ * verification is done expectedly.
+ */
+public class Helper {
+    private static final String TAG = "FsVerityTest";
+
+    private static final String FILENAME = "test.file";
+
+    private static final long BLOCK_SIZE = 4096;
+
+    @Test
+    public void prepareTest() throws Exception {
+        Context context = ApplicationProvider.getApplicationContext();
+        android.os.Bundle testArgs = InstrumentationRegistry.getArguments();
+
+        String basename = testArgs.getString("basename");
+        context.deleteFile(basename);
+
+        assertThat(testArgs).isNotNull();
+        int fileSize = Integer.parseInt(testArgs.getString("fileSize"));
+        Log.d(TAG, "Preparing test file with size " + fileSize);
+
+        byte[] bytes = new byte[8192];
+        Arrays.fill(bytes, (byte) '1');
+        try (FileOutputStream os = context.openFileOutput(basename, Context.MODE_PRIVATE)) {
+            for (int i = 0; i < fileSize; i += bytes.length) {
+                if (i + bytes.length > fileSize) {
+                    os.write(bytes, 0, fileSize % bytes.length);
+                } else {
+                    os.write(bytes);
+                }
+            }
+        }
+
+        // Enable fs-verity
+        FileIntegrityManager fim = context.getSystemService(FileIntegrityManager.class);
+        fim.setupFsVerity(context.getFileStreamPath(basename));
+    }
+
+    @Test
+    public void verifyFileRead() throws Exception {
+        Context context = ApplicationProvider.getApplicationContext();
+
+        // Collect indices that the backing blocks are supposed to be corrupted.
+        android.os.Bundle testArgs = InstrumentationRegistry.getArguments();
+        assertThat(testArgs).isNotNull();
+        String filePath = testArgs.getString("filePath");
+        String csv = testArgs.getString("brokenBlockIndicesCsv");
+        Log.d(TAG, "brokenBlockIndicesCsv: " + csv);
+        String[] strings = csv.split(",");
+        var corrupted = new ArrayList(strings.length);
+        for (int i = 0; i < strings.length; i++) {
+            corrupted.add(Integer.parseInt(strings[i]));
+        }
+
+        // Expect the read to succeed or fail per the prior.
+        try (var file = new RandomAccessFile(filePath, "r")) {
+            long total_blocks = (file.length() + BLOCK_SIZE - 1) / BLOCK_SIZE;
+            for (int i = 0; i < (int) total_blocks; i++) {
+                file.seek(i * BLOCK_SIZE);
+                if (corrupted.contains(i)) {
+                    Log.d(TAG, "Expecting read at block #" + i + " to fail");
+                    assertThrows(IOException.class, () -> file.read());
+                } else {
+                    assertThat(file.readByte()).isEqualTo('1');
+                }
+            }
+        }
+    }
+}
diff --git a/tests/ApkVerityTest/OWNERS b/tests/FsVerityTest/OWNERS
similarity index 100%
rename from tests/ApkVerityTest/OWNERS
rename to tests/FsVerityTest/OWNERS
diff --git a/tests/FsVerityTest/TEST_MAPPING b/tests/FsVerityTest/TEST_MAPPING
new file mode 100644
index 0000000..39944be
--- /dev/null
+++ b/tests/FsVerityTest/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "postsubmit": [
+    {
+      "name": "FsVerityTest"
+    },
+    // nextgen test only runs during postsubmit.
+    {
+      "name": "FsVerityTest",
+      "keywords": ["nextgen"]
+    }
+  ]
+}
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/FsVerityTest/block_device_writer/Android.bp
similarity index 100%
rename from tests/ApkVerityTest/block_device_writer/Android.bp
rename to tests/FsVerityTest/block_device_writer/Android.bp
diff --git a/tests/ApkVerityTest/block_device_writer/block_device_writer.cpp b/tests/FsVerityTest/block_device_writer/block_device_writer.cpp
similarity index 100%
rename from tests/ApkVerityTest/block_device_writer/block_device_writer.cpp
rename to tests/FsVerityTest/block_device_writer/block_device_writer.cpp
diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/FsVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
similarity index 100%
rename from tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
rename to tests/FsVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
diff --git a/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java b/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java
new file mode 100644
index 0000000..be479f2
--- /dev/null
+++ b/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.fsverity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.annotations.RootPermissionTest;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.host.HostFlagsValueProvider;
+import android.security.Flags;
+
+import com.android.blockdevicewriter.BlockDeviceWriter;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * This test verifies fs-verity works end-to-end. There is a corresponding helper app.
+ *
+ * <p>The helper app uses a FileIntegrityManager API to enable fs-verity to a file. The host test
+ * here * tampers with the file's backing storage, then tells the helper app to read and expect
+ * success/failure on read.
+ *
+ * <p>In order to make sure a block of the file is readable only if the underlying block on disk
+ * stay intact, the test needs to bypass the filesystem and tampers with the corresponding physical
+ * address against the block device.
+ */
+@RootPermissionTest
+@RunWith(DeviceJUnit4ClassRunner.class)
+@RequiresFlagsEnabled(Flags.FLAG_FSVERITY_API)
+public class FsVerityHostTest extends BaseHostJUnit4Test {
+    private static final String TARGET_PACKAGE = "com.android.fsverity";
+
+    private static final String BASENAME = "test.file";
+    private static final String TARGET_PATH = "/data/data/" + TARGET_PACKAGE + "/files/" + BASENAME;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            HostFlagsValueProvider.createCheckFlagsRule(this::getDevice);
+
+    @Test
+    public void testFsVeritySmallFile() throws Exception {
+        prepareTest(10000);
+
+        ITestDevice device = getDevice();
+        BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 0);
+        BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 8192);
+        BlockDeviceWriter.dropCaches(device);
+
+        verifyRead(TARGET_PATH, "0,2");
+    }
+
+    @Test
+    public void testFsVerityLargerFileWithOneMoreMerkleTreeLevel() throws Exception {
+        prepareTest(128 * 4096 + 1);
+
+        ITestDevice device = getDevice();
+        BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 4096);
+        BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 100 * 4096);
+        BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 128 * 4096 + 1);
+        BlockDeviceWriter.dropCaches(device);
+
+        verifyRead(TARGET_PATH, "1,100,128");
+    }
+
+    private void prepareTest(int fileSize) throws Exception {
+        DeviceTestRunOptions options = new DeviceTestRunOptions(TARGET_PACKAGE);
+        options.setTestClassName(TARGET_PACKAGE + ".Helper");
+        options.setTestMethodName("prepareTest");
+        options.addInstrumentationArg("basename", BASENAME);
+        options.addInstrumentationArg("fileSize", String.valueOf(fileSize));
+        assertThat(runDeviceTests(options)).isTrue();
+    }
+
+    private void verifyRead(String path, String indicesCsv) throws Exception {
+        DeviceTestRunOptions options = new DeviceTestRunOptions(TARGET_PACKAGE);
+        options.setTestClassName(TARGET_PACKAGE + ".Helper");
+        options.setTestMethodName("verifyFileRead");
+        options.addInstrumentationArg("brokenBlockIndicesCsv", indicesCsv);
+        options.addInstrumentationArg("filePath", TARGET_PATH);
+        assertThat(runDeviceTests(options)).isTrue();
+    }
+}
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp b/tests/FsVerityTest/testdata/Android.bp
similarity index 72%
copy from tests/ApkVerityTest/ApkVerityTestApp/Android.bp
copy to tests/FsVerityTest/testdata/Android.bp
index adf8f9f..2d578d3 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/Android.bp
+++ b/tests/FsVerityTest/testdata/Android.bp
@@ -18,21 +18,22 @@
     // all of the 'license_kinds' from "frameworks_base_license"
     // to get the below license kinds:
     //   SPDX-license-identifier-Apache-2.0
+    //   SPDX-license-identifier-MIT
+    //   SPDX-license-identifier-Unicode-DFS
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-android_test_helper_app {
-  name: "ApkVerityTestApp",
-  manifest: "AndroidManifest.xml",
-  srcs: ["src/**/*.java"],
+filegroup {
+    name: "ApkVerityTestKeyPem",
+    srcs: ["ApkVerityTestKey.pem"],
 }
 
-android_test_helper_app {
-  name: "ApkVerityTestAppSplit",
-  manifest: "feature_split/AndroidManifest.xml",
-  srcs: ["src/**/*.java"],
-  aaptflags: [
-      "--custom-package com.android.apkverity.feature_x",
-      "--package-id 0x80",
-  ],
+filegroup {
+    name: "ApkVerityTestCertPem",
+    srcs: ["ApkVerityTestCert.pem"],
+}
+
+filegroup {
+    name: "ApkVerityTestCertDer",
+    srcs: ["ApkVerityTestCert.der"],
 }
diff --git a/tests/ApkVerityTest/testdata/ApkVerityTestCert.der b/tests/FsVerityTest/testdata/ApkVerityTestCert.der
similarity index 100%
rename from tests/ApkVerityTest/testdata/ApkVerityTestCert.der
rename to tests/FsVerityTest/testdata/ApkVerityTestCert.der
Binary files differ
diff --git a/tests/ApkVerityTest/testdata/ApkVerityTestCert.pem b/tests/FsVerityTest/testdata/ApkVerityTestCert.pem
similarity index 100%
rename from tests/ApkVerityTest/testdata/ApkVerityTestCert.pem
rename to tests/FsVerityTest/testdata/ApkVerityTestCert.pem
diff --git a/tests/ApkVerityTest/testdata/ApkVerityTestKey.pem b/tests/FsVerityTest/testdata/ApkVerityTestKey.pem
similarity index 100%
rename from tests/ApkVerityTest/testdata/ApkVerityTestKey.pem
rename to tests/FsVerityTest/testdata/ApkVerityTestKey.pem
diff --git a/tests/SurfaceViewBufferTests/Android.bp b/tests/SurfaceViewBufferTests/Android.bp
index dc75f00..38313f8 100644
--- a/tests/SurfaceViewBufferTests/Android.bp
+++ b/tests/SurfaceViewBufferTests/Android.bp
@@ -23,7 +23,10 @@
 
 android_test {
     name: "SurfaceViewBufferTests",
-    srcs: ["**/*.java","**/*.kt"],
+    srcs: [
+        "**/*.java",
+        "**/*.kt",
+    ],
     manifest: "AndroidManifest.xml",
     test_config: "AndroidTest.xml",
     platform_apis: true,
@@ -41,6 +44,7 @@
         "kotlin-stdlib",
         "kotlinx-coroutines-android",
         "flickerlib",
+        "flickerlib-trace_processor_shell",
         "truth-prebuilt",
         "cts-wm-util",
         "CtsSurfaceValidatorLib",
@@ -60,7 +64,7 @@
         "libandroid",
     ],
     include_dirs: [
-        "system/core/include"
+        "system/core/include",
     ],
     stl: "libc++_static",
     cflags: [
diff --git a/tests/SurfaceViewBufferTests/AndroidManifest.xml b/tests/SurfaceViewBufferTests/AndroidManifest.xml
index 78415e8..798c67a 100644
--- a/tests/SurfaceViewBufferTests/AndroidManifest.xml
+++ b/tests/SurfaceViewBufferTests/AndroidManifest.xml
@@ -29,9 +29,12 @@
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
     <!-- Save failed test bitmap images !-->
     <uses-permission android:name="android.Manifest.permission.WRITE_EXTERNAL_STORAGE"/>
+    <!-- Allow the test to connect to perfetto trace processor -->
+    <uses-permission android:name="android.permission.INTERNET"/>
 
     <application android:allowBackup="false"
-         android:supportsRtl="true">
+         android:supportsRtl="true"
+         android:networkSecurityConfig="@xml/network_security_config">
         <activity android:name=".MainActivity"
                   android:taskAffinity="com.android.test.MainActivity"
                   android:theme="@style/AppTheme"
diff --git a/tests/SurfaceViewBufferTests/res/xml/network_security_config.xml b/tests/SurfaceViewBufferTests/res/xml/network_security_config.xml
new file mode 100644
index 0000000..4bd9ca0
--- /dev/null
+++ b/tests/SurfaceViewBufferTests/res/xml/network_security_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">localhost</domain>
+    </domain-config>
+</network-security-config>
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
index a38019d..b03b733 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -21,11 +21,9 @@
 import android.graphics.Rect
 import android.util.Log
 import androidx.test.ext.junit.rules.ActivityScenarioRule
-import android.tools.common.flicker.subject.layers.LayerSubject
 import android.tools.common.traces.surfaceflinger.LayersTrace
-import android.tools.device.traces.io.ResultWriter
-import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor
 import android.tools.device.traces.monitors.withSFTracing
+import android.tools.device.traces.monitors.PerfettoTraceMonitor
 import junit.framework.Assert
 import org.junit.After
 import org.junit.Before
@@ -33,6 +31,7 @@
 import java.io.FileOutputStream
 import java.io.IOException
 import java.util.concurrent.CountDownLatch
+import perfetto.protos.PerfettoConfig.SurfaceFlingerLayersConfig
 
 open class SurfaceTracingTestBase(useBlastAdapter: Boolean) :
         SurfaceViewBufferTestBase(useBlastAdapter) {
@@ -43,7 +42,7 @@
     @Before
     override fun setup() {
         super.setup()
-        stopLayerTrace()
+        PerfettoTraceMonitor.stopAllSessions()
         addSurfaceView()
     }
 
@@ -83,10 +82,6 @@
         instrumentation.waitForIdleSync()
     }
 
-    private fun stopLayerTrace() {
-        LayersTraceMonitor().stop(ResultWriter())
-    }
-
     fun checkPixels(bounds: Rect, @ColorInt color: Int) {
         val screenshot = instrumentation.getUiAutomation().takeScreenshot()
         val pixels = IntArray(screenshot.width * screenshot.height)
@@ -106,14 +101,19 @@
                         Log.e("SurfaceViewBufferTests", "Error writing bitmap to file", e)
                     }
                 }
-                Assert.assertEquals("Checking $bounds found mismatch $i,$j",
-                        Color.valueOf(color), Color.valueOf(actualColor))
+                Assert.assertEquals(
+                    "Checking $bounds found mismatch $i,$j",
+                    Color.valueOf(color),
+                    Color.valueOf(actualColor)
+                )
             }
         }
     }
 
     private companion object {
-        private const val TRACE_FLAGS =
-                (1 shl 0) or (1 shl 5) or (1 shl 6) // TRACE_CRITICAL | TRACE_BUFFERS | TRACE_SYNC
+        private val TRACE_FLAGS = listOf(
+            SurfaceFlingerLayersConfig.TraceFlag.TRACE_FLAG_BUFFERS,
+            SurfaceFlingerLayersConfig.TraceFlag.TRACE_FLAG_VIRTUAL_DISPLAYS,
+        )
     }
 }
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/Android.bp b/tests/TaskOrganizerTest/Android.bp
index 9b72d35..bf12f42 100644
--- a/tests/TaskOrganizerTest/Android.bp
+++ b/tests/TaskOrganizerTest/Android.bp
@@ -25,7 +25,10 @@
 
 android_test {
     name: "TaskOrganizerTest",
-    srcs: ["**/*.java","**/*.kt"],
+    srcs: [
+        "**/*.java",
+        "**/*.kt",
+    ],
     manifest: "AndroidManifest.xml",
     test_config: "AndroidTest.xml",
     platform_apis: true,
@@ -39,6 +42,7 @@
         "kotlin-stdlib",
         "kotlinx-coroutines-android",
         "flickerlib",
+        "flickerlib-trace_processor_shell",
         "truth-prebuilt",
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/TaskOrganizerTest/AndroidManifest.xml b/tests/TaskOrganizerTest/AndroidManifest.xml
index 1f1bd3e..cbeb246 100644
--- a/tests/TaskOrganizerTest/AndroidManifest.xml
+++ b/tests/TaskOrganizerTest/AndroidManifest.xml
@@ -16,9 +16,11 @@
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <!-- Allow the test to connect to perfetto trace processor -->
+    <uses-permission android:name="android.permission.INTERNET"/>
     <!-- Enable / Disable tracing !-->
     <uses-permission android:name="android.permission.DUMP" />
-    <application>
+    <application android:networkSecurityConfig="@xml/network_security_config">
       <activity android:name="TaskOrganizerMultiWindowTest"
            android:label="TaskOrganizer MW Test"
            android:exported="true"
diff --git a/tests/TaskOrganizerTest/res/xml/network_security_config.xml b/tests/TaskOrganizerTest/res/xml/network_security_config.xml
new file mode 100644
index 0000000..e450a99
--- /dev/null
+++ b/tests/TaskOrganizerTest/res/xml/network_security_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+~ Copyright (C) 2023 The Android Open Source Project
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~      http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">localhost</domain>
+    </domain-config>
+</network-security-config>
\ No newline at end of file
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
index 6f4f7b1..2c7905d 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -22,8 +22,6 @@
 import androidx.test.runner.AndroidJUnit4
 import android.tools.common.datatypes.Size
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.device.traces.io.ResultWriter
-import android.tools.device.traces.monitors.surfaceflinger.LayersTraceMonitor
 import android.tools.device.traces.monitors.withSFTracing
 import org.junit.After
 import org.junit.Before
@@ -41,16 +39,13 @@
     @get:Rule
     var scenarioRule: ActivityScenarioRule<TaskOrganizerMultiWindowTest> =
             ActivityScenarioRule<TaskOrganizerMultiWindowTest>(
-                    TaskOrganizerMultiWindowTest::class.java)
+                    TaskOrganizerMultiWindowTest::class.java
+            )
 
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
 
     @Before
     fun setup() {
-        val monitor = LayersTraceMonitor()
-        if (monitor.isEnabled) {
-            monitor.stop(ResultWriter())
-        }
         val firstTaskBounds = Rect(0, 0, 1080, 1000)
         val secondTaskBounds = Rect(0, 1000, 1080, 2000)
 
@@ -71,7 +66,7 @@
         val firstBounds = Rect(0, 0, 1080, 800)
         val secondBounds = Rect(0, 1000, 1080, 1800)
 
-        val trace = withSFTracing(TRACE_FLAGS) {
+        val trace = withSFTracing() {
             lateinit var resizeReadyLatch: CountDownLatch
             scenarioRule.getScenario().onActivity {
                 resizeReadyLatch = it.resizeTaskView(firstBounds, secondBounds)
@@ -106,7 +101,6 @@
     }
 
     companion object {
-        private const val TRACE_FLAGS = 0x1 // TRACE_CRITICAL
         private const val FIRST_ACTIVITY = "Activity1"
         private const val SECOND_ACTIVITY = "Activity2"
     }
diff --git a/tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt b/tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt
similarity index 100%
rename from tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt
rename to tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index b94d14f..0aaf3e8 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -7,7 +7,9 @@
 #include "AaptUtil.h"
 #include "Main.h"
 #include "ResourceFilter.h"
+#include "Utils.h"
 
+#include <androidfw/PathUtils.h>
 #include <utils/misc.h>
 #include <utils/SortedVector.h>
 
@@ -96,7 +98,7 @@
     char *matchedPattern = NULL;
 
     String8 fullPath(root);
-    fullPath.appendPath(path);
+    appendPath(fullPath, String8(path));
     FileType type = getFileType(fullPath);
 
     int plen = strlen(path);
@@ -508,7 +510,7 @@
 {
     if (hasData()) {
         String8 name(mGroupEntry.toDirName(String8()));
-        name.appendPath(mPath);
+        appendPath(name, mPath);
         name.append(" #generated");
         return name;
     }
@@ -615,7 +617,7 @@
     String8 remain = path;
 
     sp<AaptDir> subdir = this;
-    while (name = remain.walkPath(&remain), remain != "") {
+    while (name = walkPath(remain, &remain), remain != "") {
         subdir = subdir->makeDir(name);
     }
 
@@ -623,7 +625,7 @@
     if (i >= 0) {
         return subdir->mDirs.valueAt(i);
     }
-    sp<AaptDir> dir = new AaptDir(name, subdir->mPath.appendPathCopy(name));
+    sp<AaptDir> dir = new AaptDir(name, appendPathCopy(subdir->mPath, name));
     subdir->mDirs.add(name, dir);
     return dir;
 }
@@ -645,7 +647,7 @@
     if (mFiles.indexOfKey(leafName) >= 0) {
         group = mFiles.valueFor(leafName);
     } else {
-        group = new AaptGroup(leafName, mPath.appendPathCopy(leafName));
+        group = new AaptGroup(leafName, appendPathCopy(mPath, leafName));
         mFiles.add(leafName, group);
     }
 
@@ -684,7 +686,7 @@
             // Add fully qualified path for dependency purposes
             // if we're collecting them
             if (fullResPaths != NULL) {
-                fullResPaths->add(srcDir.appendPathCopy(name));
+                fullResPaths->add(appendPathCopy(srcDir, name));
             }
         }
         closedir(dir);
@@ -701,7 +703,7 @@
         String8 pathName(srcDir);
         FileType type;
 
-        pathName.appendPath(fileNames[i].c_str());
+        appendPath(pathName, fileNames[i]);
         type = getFileType(pathName.c_str());
         if (type == kFileTypeDirectory) {
             sp<AaptDir> subdir;
@@ -709,7 +711,7 @@
             if (mDirs.indexOfKey(fileNames[i]) >= 0) {
                 subdir = mDirs.valueFor(fileNames[i]);
             } else {
-                subdir = new AaptDir(fileNames[i], mPath.appendPathCopy(fileNames[i]));
+                subdir = new AaptDir(fileNames[i], appendPathCopy(mPath, fileNames[i]));
                 notAdded = true;
             }
             ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
@@ -821,11 +823,11 @@
 {
     if (mFiles.size() > 0) {
         // Arbitrarily pull the first file out of the list as the source dir.
-        return mFiles.valueAt(0)->getPrintableSource().getPathDir();
+        return getPathDir(mFiles.valueAt(0)->getPrintableSource());
     }
     if (mDirs.size() > 0) {
         // Or arbitrarily pull the first dir out of the list as the source dir.
-        return mDirs.valueAt(0)->getPrintableSource().getPathDir();
+        return getPathDir(mDirs.valueAt(0)->getPrintableSource());
     }
 
     // Should never hit this case, but to be safe...
@@ -908,8 +910,8 @@
     sp<AaptFile> file;
     String8 root, remain(filePath), partialPath;
     while (remain.length() > 0) {
-        root = remain.walkPath(&remain);
-        partialPath.appendPath(root);
+        root = walkPath(remain, &remain);
+        appendPath(partialPath, root);
 
         const String8 rootStr(root);
 
@@ -924,7 +926,7 @@
                     return NULL;
                 }
             }
-            file = new AaptFile(srcDir.appendPathCopy(filePath), entry, resType);
+            file = new AaptFile(appendPathCopy(srcDir, filePath), entry, resType);
             status_t res = group->addFile(file);
             if (res != NO_ERROR) {
                 return NULL;
@@ -981,7 +983,7 @@
     if (bundle->getAndroidManifestFile() != NULL) {
         // place at root of zip.
         String8 srcFile(bundle->getAndroidManifestFile());
-        addFile(srcFile.getPathLeaf(), AaptGroupEntry(), srcFile.getPathDir(),
+        addFile(getPathLeaf(srcFile), AaptGroupEntry(), getPathDir(srcFile),
                 NULL, String8());
         totalCount++;
     }
@@ -1154,7 +1156,7 @@
         }
 
         String8 subdirName(srcDir);
-        subdirName.appendPath(entry->d_name);
+        appendPath(subdirName, entry->d_name);
 
         AaptGroupEntry group;
         String8 resType;
@@ -1239,16 +1241,16 @@
 
         String8 entryName(entry->getFileName());
 
-        String8 dirName = entryName.getPathDir();
+        String8 dirName = getPathDir(entryName);
         sp<AaptDir> dir = dirName == "" ? this : makeDir(dirName);
 
         String8 resType;
         AaptGroupEntry kind;
 
         String8 remain;
-        if (entryName.walkPath(&remain) == kResourceDir) {
+        if (walkPath(entryName, &remain) == kResourceDir) {
             // these are the resources, pull their type out of the directory name
-            kind.initFromDirName(remain.walkPath().c_str(), &resType);
+            kind.initFromDirName(walkPath(remain).c_str(), &resType);
         } else {
             // these are untyped and don't have an AaptGroupEntry
         }
@@ -1258,10 +1260,10 @@
         }
 
         // use the one from the zip file if they both exist.
-        dir->removeFile(entryName.getPathLeaf());
+        dir->removeFile(getPathLeaf(entryName));
 
         sp<AaptFile> file = new AaptFile(entryName, kind, resType);
-        status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
+        status_t err = dir->addLeafFile(getPathLeaf(entryName), file);
         if (err != NO_ERROR) {
             fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.c_str());
             count = err;
@@ -1374,7 +1376,7 @@
                     // containing no entries.
                     continue;
                 }
-                if (file->getPath().getPathExtension() == ".xml") {
+                if (getPathExtension(file->getPath()) == ".xml") {
                     // We can't remove .xml files at this point, because when
                     // we parse them they may add identifier resources, so
                     // removing them can cause our resource identifiers to
@@ -1411,7 +1413,7 @@
                     // containing no entries.
                     continue;
                 }
-                if (file->getPath().getPathExtension() == ".xml") {
+                if (getPathExtension(file->getPath()) == ".xml") {
                     // We can't remove .xml files at this point, because when
                     // we parse them they may add identifier resources, so
                     // removing them can cause our resource identifiers to
@@ -1540,7 +1542,7 @@
     }
 
     const String8& featureOfBase = bundle->getFeatureOfPackage();
-    if (!featureOfBase.isEmpty()) {
+    if (!featureOfBase.empty()) {
         if (bundle->getVerbose()) {
             printf("Including base feature resources from package: %s\n",
                     featureOfBase.c_str());
diff --git a/tools/aapt/Android.bp b/tools/aapt/Android.bp
index cecd95a..68db56d 100644
--- a/tools/aapt/Android.bp
+++ b/tools/aapt/Android.bp
@@ -51,6 +51,10 @@
         "libz",
     ],
 
+    whole_static_libs: [
+        "libandroidfw_pathutils",
+    ],
+
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h
index 2dc143c..dc5493f 100644
--- a/tools/aapt/CacheUpdater.h
+++ b/tools/aapt/CacheUpdater.h
@@ -7,6 +7,7 @@
 #ifndef CACHE_UPDATER_H
 #define CACHE_UPDATER_H
 
+#include <androidfw/PathUtils.h>
 #include <utils/String8.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -16,6 +17,8 @@
 #include <direct.h>
 #endif
 
+#include "Utils.h"
+
 using namespace android;
 
 /** CacheUpdater
@@ -72,14 +75,14 @@
             do {
                 // As we remove the end of existsPath add it to
                 // the string of paths to create.
-                toCreate = existsPath.getPathLeaf().appendPath(toCreate);
-                existsPath = existsPath.getPathDir();
+                toCreate = appendPathCopy(getPathLeaf(existsPath), toCreate);
+                existsPath = getPathDir(existsPath);
             } while (stat(existsPath.c_str(),&s) == -1);
 
             // Walk forwards and build directories as we go
             do {
                 // Advance to the next segment of the path
-                existsPath.appendPath(toCreate.walkPath(&remains));
+                appendPath(existsPath, walkPath(toCreate, &remains));
                 toCreate = remains;
 #ifdef _WIN32
                 _mkdir(existsPath.c_str());
@@ -101,7 +104,7 @@
     virtual void processImage(String8 source, String8 dest)
     {
         // Make sure we're trying to write to a directory that is extant
-        ensureDirectoriesExist(dest.getPathDir());
+        ensureDirectoriesExist(getPathDir(dest));
 
         preProcessImageToCache(bundle, source, dest);
     };
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 5a06b10..800466a 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -12,6 +12,7 @@
 #include "ResourceTable.h"
 #include "XMLNode.h"
 
+#include <androidfw/PathUtils.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/List.h>
@@ -1133,7 +1134,7 @@
                 if (code == ResXMLTree::END_TAG) {
                     depth--;
                     if (depth < 2) {
-                        if (withinSupportsInput && !supportedInput.isEmpty()) {
+                        if (withinSupportsInput && !supportedInput.empty()) {
                             printf("supports-input: '");
                             const size_t N = supportedInput.size();
                             for (size_t i=0; i<N; i++) {
@@ -1300,7 +1301,7 @@
                             ResTable::normalizeForOutput(versionName.c_str()).c_str());
 
                     String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
-                    if (!splitName.isEmpty()) {
+                    if (!splitName.empty()) {
                         printf(" split='%s'", ResTable::normalizeForOutput(
                                     splitName.c_str()).c_str());
                     }
@@ -2486,12 +2487,12 @@
     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
         const char* fileName = bundle->getFileSpecEntry(i);
 
-        if (strcasecmp(String8(fileName).getPathExtension().c_str(), ".gz") == 0) {
+        if (strcasecmp(getPathExtension(String8(fileName)).c_str(), ".gz") == 0) {
             printf(" '%s'... (from gzip)\n", fileName);
-            result = zip->addGzip(fileName, String8(fileName).getBasePath().c_str(), NULL);
+            result = zip->addGzip(fileName, getBasePath(String8(fileName)).c_str(), NULL);
         } else {
             if (bundle->getJunkPath()) {
-                String8 storageName = String8(fileName).getPathLeaf();
+                String8 storageName = getPathLeaf(String8(fileName));
                 printf(" '%s' as '%s'...\n", fileName,
                         ResTable::normalizeForOutput(storageName.c_str()).c_str());
                 result = zip->add(fileName, storageName.c_str(),
@@ -2617,10 +2618,10 @@
         return original;
     }
 
-    String8 ext(original.getPathExtension());
+    String8 ext(getPathExtension(original));
     if (ext == String8(".apk")) {
         return String8::format("%s_%s%s",
-                original.getBasePath().c_str(),
+                getBasePath(original).c_str(),
                 split->getDirectorySafeName().c_str(),
                 ext.c_str());
     }
@@ -2756,7 +2757,7 @@
             // generate the dependency file in the R.java package subdirectory
             // e.g. gen/com/foo/app/R.java.d
             dependencyFile = String8(bundle->getRClassDir());
-            dependencyFile.appendPath("R.java.d");
+            appendPath(dependencyFile, "R.java.d");
         }
         // Make sure we have a clean dependency file to start with
         fp = fopen(dependencyFile, "w");
diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp
index 1f2febe..e731ce0 100644
--- a/tools/aapt/CrunchCache.cpp
+++ b/tools/aapt/CrunchCache.cpp
@@ -5,6 +5,7 @@
 // This file defines functions laid out and documented in
 // CrunchCache.h
 
+#include <androidfw/PathUtils.h>
 #include <utils/Compat.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
@@ -52,15 +53,15 @@
         relativePath = String8(rPathPtr + offset);
 
         if (forceOverwrite || needsUpdating(relativePath)) {
-            cu->processImage(mSourcePath.appendPathCopy(relativePath),
-                             mDestPath.appendPathCopy(relativePath));
+            cu->processImage(appendPathCopy(mSourcePath, relativePath),
+                             appendPathCopy(mDestPath, relativePath));
             numFilesUpdated++;
             // crunchFile(relativePath);
         }
         // Delete this file from the source files and (if it exists) from the
         // dest files.
         mSourceFiles.removeItemsAt(0);
-        mDestFiles.removeItem(mDestPath.appendPathCopy(relativePath));
+        mDestFiles.removeItem(appendPathCopy(mDestPath, relativePath));
     }
 
     // Iterate through what's left of destFiles and delete leftovers
@@ -99,7 +100,7 @@
     // Retrieve modification dates for this file entry under the source and
     // cache directory trees. The vectors will return a modification date of 0
     // if the file doesn't exist.
-    time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath));
-    time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath));
+    time_t sourceDate = mSourceFiles.valueFor(appendPathCopy(mSourcePath, relativePath));
+    time_t destDate = mDestFiles.valueFor(appendPathCopy(mDestPath, relativePath));
     return sourceDate > destDate;
 }
diff --git a/tools/aapt/DirectoryWalker.h b/tools/aapt/DirectoryWalker.h
index cea3a6e..7f60d4d 100644
--- a/tools/aapt/DirectoryWalker.h
+++ b/tools/aapt/DirectoryWalker.h
@@ -7,6 +7,7 @@
 #ifndef DIRECTORYWALKER_H
 #define DIRECTORYWALKER_H
 
+#include <androidfw/PathUtils.h>
 #include <dirent.h>
 #include <sys/types.h>
 #include <sys/param.h>
@@ -77,7 +78,7 @@
 
         mEntry = *entryPtr;
         // Get stats
-        String8 fullPath = mBasePath.appendPathCopy(mEntry.d_name);
+        String8 fullPath = appendPathCopy(mBasePath, mEntry.d_name);
         stat(fullPath.c_str(),&mStats);
         return &mEntry;
     };
diff --git a/tools/aapt/FileFinder.cpp b/tools/aapt/FileFinder.cpp
index a5c19806..69a8fa9 100644
--- a/tools/aapt/FileFinder.cpp
+++ b/tools/aapt/FileFinder.cpp
@@ -5,6 +5,7 @@
 // File Finder implementation.
 // Implementation for the functions declared and documented in FileFinder.h
 
+#include <androidfw/PathUtils.h>
 #include <utils/Vector.h>
 #include <utils/String8.h>
 #include <utils/KeyedVector.h>
@@ -57,7 +58,7 @@
         if (entry->d_name[0] == '.') // Skip hidden files and directories
             continue;
 
-        String8 fullPath = basePath.appendPathCopy(entryName);
+        String8 fullPath = appendPathCopy(basePath, entryName);
         // If this entry is a directory we'll recurse into it
         if (isDirectory(fullPath.c_str()) ) {
             DirectoryWalker* copy = dw->clone();
@@ -83,10 +84,10 @@
 {
     // Loop over the extensions, checking for a match
     bool done = false;
-    String8 ext(path.getPathExtension());
+    String8 ext(getPathExtension(path));
     ext.toLower();
     for (size_t i = 0; i < extensions.size() && !done; ++i) {
-        String8 ext2 = extensions[i].getPathExtension();
+        String8 ext2 = getPathExtension(extensions[i]);
         ext2.toLower();
         // Compare the extensions. If a match is found, add to storage.
         if (ext == ext2) {
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index c6c7e96..cd4de90 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -8,6 +8,7 @@
 
 #include "Images.h"
 
+#include <androidfw/PathUtils.h>
 #include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
 
@@ -1357,7 +1358,7 @@
 status_t preProcessImage(const Bundle* bundle, const sp<AaptAssets>& /* assets */,
                          const sp<AaptFile>& file, String8* /* outNewLeafName */)
 {
-    String8 ext(file->getPath().getPathExtension());
+    String8 ext(getPathExtension(file->getPath()));
 
     // We currently only process PNG images.
     if (strcmp(ext.c_str(), ".png") != 0) {
@@ -1518,7 +1519,7 @@
 
     // Check to see if we're dealing with a 9-patch
     // If we are, process appropriately
-    if (source.getBasePath().getPathExtension() == ".9")  {
+    if (getPathExtension(getBasePath(source)) == ".9")  {
         if (do_9patch(source.c_str(), &imageInfo) != NO_ERROR) {
             return error;
         }
@@ -1584,12 +1585,12 @@
 status_t postProcessImage(const Bundle* bundle, const sp<AaptAssets>& assets,
                           ResourceTable* table, const sp<AaptFile>& file)
 {
-    String8 ext(file->getPath().getPathExtension());
+    String8 ext(getPathExtension(file->getPath()));
 
     // At this point, now that we have all the resource data, all we need to
     // do is compile XML files.
     if (strcmp(ext.c_str(), ".xml") == 0) {
-        String16 resourceName(parseResourceName(file->getSourceFile().getPathLeaf()));
+        String16 resourceName(parseResourceName(getPathLeaf(file->getSourceFile())));
         return compileXmlFile(bundle, assets, resourceName, file, table);
     }
 
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index a7ff5fa..5e0f87f 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -10,6 +10,7 @@
 #include "ResourceFilter.h"
 #include "Utils.h"
 
+#include <androidfw/PathUtils.h>
 #include <androidfw/misc.h>
 
 #include <utils/Log.h>
@@ -170,7 +171,7 @@
     /* anything here? */
     if (zip->getNumEntries() == 0) {
         if (bundle->getVerbose()) {
-            printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().c_str());
+            printf("Archive is empty -- removing %s\n", getPathLeaf(outputFile).c_str());
         }
         delete zip;        // close the file so we can remove it in Win32
         zip = NULL;
@@ -274,9 +275,9 @@
         return true;
     }
 
-    if (strcasecmp(storageName.getPathExtension().c_str(), ".gz") == 0) {
+    if (strcasecmp(getPathExtension(storageName).c_str(), ".gz") == 0) {
         fromGzip = true;
-        storageName = storageName.getBasePath();
+        storageName = getBasePath(storageName);
     }
 
     if (bundle->getUpdate()) {
@@ -366,7 +367,7 @@
  */
 bool okayToCompress(Bundle* bundle, const String8& pathName)
 {
-    String8 ext = pathName.getPathExtension();
+    String8 ext = getPathExtension(pathName);
     int i;
 
     if (ext.length() == 0)
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 9c944e0..3a198fd 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -19,6 +19,8 @@
 #include "WorkQueue.h"
 #include "XMLNode.h"
 
+#include <androidfw/PathUtils.h>
+
 #include <algorithm>
 
 // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
@@ -143,8 +145,8 @@
                         mParams.inputFlags, mParams.navigation);
             }
             mPath = "res";
-            mPath.appendPath(file->getGroupEntry().toDirName(mResType));
-            mPath.appendPath(leaf);
+            appendPath(mPath, file->getGroupEntry().toDirName(mResType));
+            appendPath(mPath, leaf);
             mBaseName = parseResourceName(leaf);
             if (mBaseName == "") {
                 fprintf(stderr, "Error: malformed resource filename %s\n",
@@ -779,7 +781,7 @@
         if (kIsDebug) {
             printf("Qualifying class '%s' to '%s'", name.c_str(), className.c_str());
         }
-        attr->string.setTo(String16(className));
+        attr->string = String16(className);
     }
 }
 
@@ -969,7 +971,7 @@
             return UNKNOWN_ERROR;
         }
         String8 origPackage(attr->string);
-        attr->string.setTo(String16(manifestPackageNameOverride));
+        attr->string = String16(manifestPackageNameOverride);
         if (kIsDebug) {
             printf("Overriding package '%s' to be '%s'\n", origPackage.c_str(),
                     manifestPackageNameOverride);
@@ -1007,7 +1009,7 @@
                 XMLNode::attribute_entry* attr = child->editAttribute(
                         String16(RESOURCES_ANDROID_NAMESPACE), String16("targetPackage"));
                 if (attr != NULL) {
-                    attr->string.setTo(String16(instrumentationPackageNameOverride));
+                    attr->string = String16(instrumentationPackageNameOverride);
                 }
             }
         }
@@ -1285,7 +1287,7 @@
         packageType = ResourceTable::SharedLibrary;
     } else if (bundle->getExtending()) {
         packageType = ResourceTable::System;
-    } else if (!bundle->getFeatureOfPackage().isEmpty()) {
+    } else if (!bundle->getFeatureOfPackage().empty()) {
         packageType = ResourceTable::AppFeature;
     }
 
@@ -1686,7 +1688,7 @@
         ResourceDirIterator it(fonts, String8("font"));
         while ((err=it.next()) == NO_ERROR) {
             // fonts can be resources other than xml.
-            if (it.getFile()->getPath().getPathExtension() == ".xml") {
+            if (getPathExtension(it.getFile()->getPath()) == ".xml") {
                 String8 src = it.getFile()->getPrintableSource();
                 err = compileXmlFile(bundle, assets, String16(it.getBaseName()),
                         it.getFile(), &table, xmlFlags);
@@ -1716,7 +1718,7 @@
                              workItem.file, &table, xmlCompilationFlags);
 
         if (err == NO_ERROR && workItem.file->hasData()) {
-            assets->addResource(workItem.resPath.getPathLeaf(),
+            assets->addResource(getPathLeaf(workItem.resPath),
                                 workItem.resPath,
                                 workItem.file,
                                 workItem.file->getResourceType());
@@ -2851,7 +2853,7 @@
                 s++;
                 if (s > last && (*s == '.' || *s == 0)) {
                     String8 part(last, s-last);
-                    dest.appendPath(part);
+                    appendPath(dest, part);
 #ifdef _WIN32
                     _mkdir(dest.c_str());
 #else
@@ -2861,7 +2863,7 @@
                 }
             } while (*s);
         }
-        dest.appendPath(className);
+        appendPath(dest, className);
         dest.append(".java");
         FILE* fp = fopen(dest.c_str(), "w+");
         if (fp == NULL) {
@@ -2892,7 +2894,7 @@
 
         if (textSymbolsDest != NULL && R == className) {
             String8 textDest(textSymbolsDest);
-            textDest.appendPath(className);
+            appendPath(textDest, className);
             textDest.append(".txt");
 
             FILE* fp = fopen(textDest.c_str(), "w+");
@@ -2918,7 +2920,7 @@
         if (bundle->getGenDependencies() && R == className) {
             // Add this R.java to the dependency file
             String8 dependencyFile(bundle->getRClassDir());
-            dependencyFile.appendPath("R.java.d");
+            appendPath(dependencyFile, "R.java.d");
 
             FILE *fp = fopen(dependencyFile.c_str(), "a");
             fprintf(fp,"%s \\\n", dest.c_str());
@@ -3144,7 +3146,7 @@
 
     tree.restart();
 
-    if (!startTags.isEmpty()) {
+    if (!startTags.empty()) {
         bool haveStart = false;
         while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
             if (code != ResXMLTree::START_TAG) {
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 449e080..9fb7319 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -14,6 +14,7 @@
 #include "Utils.h"
 
 #include <algorithm>
+#include <androidfw/PathUtils.h>
 #include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
 #include <utils/TypeHelpers.h>
@@ -83,7 +84,7 @@
         sp<AaptDir> resDir = assets->getDirs().valueFor(String8("res"));
         sp<AaptDir> dir = resDir->getDirs().valueFor(target->getGroupEntry().toDirName(
                 target->getResourceType()));
-        dir->removeFile(target->getPath().getPathLeaf());
+        dir->removeFile(getPathLeaf(target->getPath()));
         return NO_ERROR;
     }
 
@@ -1363,11 +1364,11 @@
                     size_t length;
                     const char16_t* attr = block.getAttributeName(i, &length);
                     if (strcmp16(attr, name16.c_str()) == 0) {
-                        name.setTo(block.getAttributeStringValue(i, &length));
+                        name = String16(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, translatable16.c_str()) == 0) {
-                        translatable.setTo(block.getAttributeStringValue(i, &length));
+                        translatable = String16(block.getAttributeStringValue(i, &length));
                     } else if (strcmp16(attr, formatted16.c_str()) == 0) {
-                        formatted.setTo(block.getAttributeStringValue(i, &length));
+                        formatted = String16(block.getAttributeStringValue(i, &length));
                     }
                 }
                 
@@ -1541,7 +1542,7 @@
                 } else {
                     ssize_t sep = ident.findLast('.');
                     if (sep >= 0) {
-                        parentIdent.setTo(ident, sep);
+                        parentIdent = String16(ident, sep);
                     }
                 }
 
@@ -1813,7 +1814,7 @@
     mTypeIdOffset = findLargestTypeIdForPackage(assets->getIncludedResources(), mAssetsPackage);
 
     const String8& featureAfter = bundle->getFeatureAfterPackage();
-    if (!featureAfter.isEmpty()) {
+    if (!featureAfter.empty()) {
         AssetManager featureAssetManager;
         if (!featureAssetManager.addAssetPath(featureAfter, NULL)) {
             fprintf(stderr, "ERROR: Feature package '%s' not found.\n",
@@ -1823,7 +1824,7 @@
 
         const ResTable& featureTable = featureAssetManager.getResources(false);
         mTypeIdOffset = std::max(mTypeIdOffset,
-                findLargestTypeIdForPackage(featureTable, mAssetsPackage)); 
+                findLargestTypeIdForPackage(featureTable, mAssetsPackage));
     }
 
     return NO_ERROR;
@@ -2831,10 +2832,10 @@
                 String8 config;
                 comma = strchr(start, ',');
                 if (comma != NULL) {
-                    config.setTo(start, comma - start);
+                    config = String8(start, comma - start);
                     start = comma + 1;
                 } else {
-                    config.setTo(start);
+                    config = start;
                 }
 
                 if (!locale.initFromFilterString(config)) {
@@ -3252,7 +3253,7 @@
 
             // If we're building splits, then each invocation of the flattening
             // step will have 'missing' entries. Don't warn/error for this case.
-            if (bundle->getSplitConfigurations().isEmpty()) {
+            if (bundle->getSplitConfigurations().empty()) {
                 bool missing_entry = false;
                 const char* log_prefix = bundle->getErrorOnMissingConfigEntry() ?
                         "error" : "warning";
@@ -4858,7 +4859,7 @@
 
     Vector<sp<XMLNode> > nodesToVisit;
     nodesToVisit.push(root);
-    while (!nodesToVisit.isEmpty()) {
+    while (!nodesToVisit.empty()) {
         sp<XMLNode> node = nodesToVisit.top();
         nodesToVisit.pop();
 
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index e130286..354a65c 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -78,7 +78,7 @@
         break;
     }
     
-    if (!this->file.isEmpty()) {
+    if (!this->file.empty()) {
         if (this->line >= 0) {
             fprintf(to, "%s:%d: %s%s\n", this->file.c_str(), this->line, type, this->error.c_str());
         } else {
diff --git a/tools/aapt/Utils.cpp b/tools/aapt/Utils.cpp
index 36b018e..946916a 100644
--- a/tools/aapt/Utils.cpp
+++ b/tools/aapt/Utils.cpp
@@ -36,3 +36,26 @@
     }
 #endif
 }
+
+String8 walkPath(const String8& path, String8* outRemains) {
+    const char* cp;
+    const char* const str = path.c_str();
+    const char* buf = str;
+
+    cp = strchr(buf, OS_PATH_SEPARATOR);
+    if (cp == buf) {
+        // don't include a leading '/'.
+        buf = buf + 1;
+        cp = strchr(buf, OS_PATH_SEPARATOR);
+    }
+
+    if (cp == nullptr) {
+        String8 res = buf != str ? String8(buf) : path;
+        if (outRemains) *outRemains = String8();
+        return res;
+    }
+
+    String8 res(buf, cp - buf);
+    if (outRemains) *outRemains = String8(cp + 1);
+    return res;
+}
diff --git a/tools/aapt/Utils.h b/tools/aapt/Utils.h
index 8eb5941..f0d6979 100644
--- a/tools/aapt/Utils.h
+++ b/tools/aapt/Utils.h
@@ -26,3 +26,13 @@
 // If the default OS separator is backslash, this converts all
 // backslashes to slashes, in-place. Otherwise it does nothing.
 void convertToResPath(android::String8&);
+
+/**
+ * Retrieve the front (root dir) component.  Optionally also return the
+ * remaining components.
+ *
+ * "/tmp/foo/bar.c" --> "tmp" (remain = "foo/bar.c")
+ * "/tmp" --> "tmp" (remain = "")
+ * "bar.c" --> "bar.c" (remain = "")
+ */
+android::String8 walkPath(const android::String8& path, android::String8* outRemains = nullptr);
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index e270a73..a887ac9 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -334,9 +334,9 @@
             String16 spanTag;
             ssize_t semi = span.name.findFirst(';');
             if (semi >= 0) {
-                spanTag.setTo(span.name.c_str(), semi);
+                spanTag = String16(span.name.c_str(), semi);
             } else {
-                spanTag.setTo(span.name);
+                spanTag = span.name;
             }
             if (strcmp16(inXml->getElementName(&len), spanTag.c_str()) != 0) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error(
@@ -393,7 +393,7 @@
         // later as part of the overall type conversion.  Return to the
         // client the raw unprocessed text.
         rawString.append(curString);
-        outString->setTo(rawString);
+        *outString = rawString;
     }
 
     return NO_ERROR;
diff --git a/tools/aapt2/DominatorTree_test.cpp b/tools/aapt2/DominatorTree_test.cpp
index 52949da..a0679a6 100644
--- a/tools/aapt2/DominatorTree_test.cpp
+++ b/tools/aapt2/DominatorTree_test.cpp
@@ -50,8 +50,7 @@
  private:
   void VisitConfig(const DominatorTree::Node* node, const int indent) {
     auto config_string = node->value()->config.toString();
-    buffer_ << std::string(indent, ' ')
-            << (config_string.isEmpty() ? "<default>" : config_string)
+    buffer_ << std::string(indent, ' ') << (config_string.empty() ? "<default>" : config_string)
             << std::endl;
   }
 
diff --git a/tools/hoststubgen/.gitignore b/tools/hoststubgen/.gitignore
new file mode 100644
index 0000000..6453bde
--- /dev/null
+++ b/tools/hoststubgen/.gitignore
@@ -0,0 +1,3 @@
+out/
+*-out/
+*.log
diff --git a/tools/hoststubgen/OWNERS b/tools/hoststubgen/OWNERS
new file mode 100644
index 0000000..a8c5321
--- /dev/null
+++ b/tools/hoststubgen/OWNERS
@@ -0,0 +1,3 @@
+omakoto@google.com
+jsharkey@google.com
+jaggies@google.com
diff --git a/tools/hoststubgen/README.md b/tools/hoststubgen/README.md
new file mode 100644
index 0000000..b0a1262
--- /dev/null
+++ b/tools/hoststubgen/README.md
@@ -0,0 +1,76 @@
+# HostStubGen
+
+## Overview
+
+This directory contains tools / sample code / investigation for host side test support.
+
+
+## Directories and files
+
+- `hoststubgen/`
+  Contains source code of the "hoststubgen" tool and relevant code
+
+  - `framework-policy-override.txt`
+    This file contains "policy overrides", which allows to control what goes to stub/impl without
+    having to touch the target java files. This allows quicker iteration, because you can skip
+    having to rebuild framework.jar.
+
+  - `src/`
+
+    HostStubGen tool source code.
+
+  - `annotations-src/` See `Android.bp`.
+  - `helper-framework-buildtime-src/` See `Android.bp`.
+  - `helper-framework-runtime-src/` See `Android.bp`.
+  - `helper-runtime-src/` See `Android.bp`.
+
+  - `test-tiny-framework/` See `README.md` in it.
+
+  - `test-framework` See `README.md` in it.
+
+- `scripts`
+  - `run-host-test.sh`
+
+    Run a host side test. Use it instead of `atest` for now. (`atest` works "mostly" but it has
+    problems.)
+
+  - `dump-jar.sh`
+
+    A script to dump the content of `*.class` and `*.jar` files.
+
+  - `run-all-tests.sh`
+
+    Run all tests. Many tests may fail, but at least this should run til the end.
+    (It should print `run-all-tests.sh finished` at the end)
+
+## Build and run
+
+### Building `HostStubGen` binary
+
+```
+m hoststubgen
+```
+
+### Run the tests
+
+- Run all relevant tests and test scripts. Some of thests are still expected to fail,
+  but this should print "finished, with no unexpected failures" at the end.
+
+  However, because some of the script it executes depend on internal file paths to Soong's
+  intermediate directory, some of it might fail when something changes in the build system.
+
+  We need proper build system integration to fix them.
+```
+$ ./scripts/run-all-tests.sh
+```
+
+- See also `README.md` in `test-*` directories.
+
+## TODOs, etc
+
+ - Make sure the parent's visibility is not smaller than the member's.
+
+- @HostSideTestNativeSubstitutionClass should automatically add class-keep to the substitute class.
+  (or at least check it.)
+
+ - The `HostStubGenTest-framework-test-host-test-lib` jar somehow contain all ASM classes? Figure out where the dependency is coming from.
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING
new file mode 100644
index 0000000..9703626
--- /dev/null
+++ b/tools/hoststubgen/TEST_MAPPING
@@ -0,0 +1,6 @@
+{
+    // TODO: Change to presubmit.
+    "postsubmit": [
+        { "name": "tiny-framework-dump-test" }
+    ]
+}
diff --git a/tools/hoststubgen/common.sh b/tools/hoststubgen/common.sh
new file mode 100644
index 0000000..b49ee39
--- /dev/null
+++ b/tools/hoststubgen/common.sh
@@ -0,0 +1,116 @@
+# 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.
+
+set -e # Exit at failure
+shopt -s globstar # Enable double-star wildcards (**)
+
+cd "${0%/*}" # Move to the script dir
+
+fail() {
+  echo "Error: $*" 1>&2
+  exit 1
+}
+
+# Print the arguments and then execute.
+run() {
+  echo "Running: $*" 1>&2
+  "$@"
+}
+
+# Concatenate the second and subsequent args with the first arg as a separator.
+# e.g. `join : a b c` -> prints `a:b:c`
+join() {
+  local IFS="$1"
+  shift
+  echo "$*"
+}
+
+abspath() {
+  for name in "${@}"; do
+    readlink -f $name
+  done
+}
+
+m() {
+  if (( $SKIP_BUILD )) ; then
+    echo "Skipping build: $*" 1>&2
+    return 0
+  fi
+  run ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+# Extract given jar files
+extract() {
+  for f in "${@}"; do
+    local out=$f.ext
+    run rm -fr $out
+    run mkdir -p $out
+
+    # It's too noisy, so only show the first few lines.
+    {
+      # Hmm unzipping kotlin jar files may produce a warning? Let's just add `|| true`...
+      run unzip $f -d $out || true
+    } |& sed -e '5,$d'
+    echo '  (omitting remaining output)'
+
+  done
+}
+
+# Find all *.java files in $1, and print them as Java class names.
+# For example, if there's a file `src/com/android/test/Test.java`, and you run
+# `list_all_classes_under_dir src`, then it'll print `com.android.test.Test`.
+list_all_classes_under_dir() {
+  local dir="$1"
+  ( # Use a subshell, so we won't change the current directory on the caller side.
+    cd "$dir"
+
+    # List the java files, but replace the slashes with dots, and remove the `.java` suffix.
+    ls **/*.java | sed -e 's!/!.!g' -e 's!.java$!!'
+  )
+}
+
+checkenv() {
+  # Make sure $ANDROID_BUILD_TOP is set.
+  : ${ANDROID_BUILD_TOP:?}
+
+  # Make sure ANDROID_BUILD_TOP doesn't contain whitespace.
+  set ${ANDROID_BUILD_TOP}
+  if [[ $# != 1 ]] ; then
+    fail "\$ANDROID_BUILD_TOP cannot contain whitespace."
+  fi
+}
+
+checkenv
+
+JAVAC=${JAVAC:-javac}
+JAVA=${JAVA:-java}
+JAR=${JAR:-jar}
+
+JAVAC_OPTS=${JAVAC_OPTS:--Xmaxerrs 99999 -Xlint:none}
+
+SOONG_INT=$ANDROID_BUILD_TOP/out/soong/.intermediates
+
+JUNIT_TEST_MAIN_CLASS=com.android.hoststubgen.hosthelper.HostTestSuite
+
+run_junit_test_jar() {
+  local jar="$1"
+  echo "Starting test: $jar ..."
+  run cd "${jar%/*}"
+
+  run $JAVA $JAVA_OPTS \
+      -cp $jar \
+      org.junit.runner.JUnitCore \
+      $main_class || return 1
+  return 0
+}
diff --git a/tools/hoststubgen/hoststubgen/.gitignore b/tools/hoststubgen/hoststubgen/.gitignore
new file mode 100644
index 0000000..0f38407
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/.gitignore
@@ -0,0 +1 @@
+framework-all-stub-out
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
new file mode 100644
index 0000000..a617876
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -0,0 +1,303 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// This library contains the standard hoststubgen annotations.
+java_library {
+    name: "hoststubgen-annotations",
+    srcs: [
+        "annotations-src/**/*.java",
+    ],
+    host_supported: true,
+
+    // Seems like we need it to avoid circular deps.
+    // Copied it from "app-compat-annotations".
+    sdk_version: "core_current",
+    visibility: ["//visibility:public"],
+}
+
+// This library contains helper classes used in the host side test environment at runtime.
+// This library is _not_ specific to Android APIs.
+java_library_host {
+    name: "hoststubgen-helper-runtime",
+    srcs: [
+        "helper-runtime-src/**/*.java",
+    ],
+    libs: [
+        "junit",
+        "ow2-asm",
+        "ow2-asm-analysis",
+        "ow2-asm-commons",
+        "ow2-asm-tree",
+        "ow2-asm-util",
+    ],
+    static_libs: [
+        "guava",
+    ],
+    jarjar_rules: "jarjar-rules.txt",
+    visibility: ["//visibility:public"],
+}
+
+// Host-side stub generator tool.
+java_binary_host {
+    name: "hoststubgen",
+    main_class: "com.android.hoststubgen.Main",
+    srcs: ["src/**/*.kt"],
+    static_libs: [
+        "hoststubgen-helper-runtime",
+        "ow2-asm",
+        "ow2-asm-analysis",
+        "ow2-asm-commons",
+        "ow2-asm-tree",
+        "ow2-asm-util",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// File that contains the standard command line argumetns to hoststubgen.
+filegroup {
+    name: "hoststubgen-standard-options",
+    srcs: [
+        "hoststubgen-standard-options.txt",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+hoststubgen_common_options = "$(location hoststubgen) " +
+    // "--in-jar $(location :framework-all) " +
+    // "--policy-override-file $(location framework-policy-override.txt) " +
+    "@$(location :hoststubgen-standard-options) " +
+
+    "--out-stub-jar $(location host_stub.jar) " +
+    "--out-impl-jar $(location host_impl.jar) " +
+
+    // "--keep-all-classes " + // Used it for an experiment. See KeepAllClassesFilter.
+    "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " +
+    "--gen-input-dump-file $(location hoststubgen_dump.txt) " +
+    ""
+
+// Common defaults for stub generation.
+// This one is not specific to Android APIs.
+genrule_defaults {
+    name: "hoststubgen-command-defaults",
+    tools: ["hoststubgen"],
+    srcs: [
+        ":hoststubgen-standard-options",
+    ],
+    // Create two jar files.
+    out: [
+        "host_stub.jar",
+        "host_impl.jar",
+
+        // Following files are created just as FYI.
+        "hoststubgen_keep_all.txt",
+        "hoststubgen_dump.txt",
+    ],
+    // visibility:  ["//visibility:public"],
+}
+
+// Generate the stub/impl from framework-all, with hidden APIs.
+java_genrule_host {
+    name: "framework-all-hidden-api-host",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--in-jar $(location :framework-all) " +
+        "--policy-override-file $(location framework-policy-override.txt) ",
+    srcs: [
+        ":framework-all",
+        "framework-policy-override.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Extract the stub jar from "framework-all-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-hidden-api-host-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-hidden-api-host{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Extract the impl jar from "framework-all-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-hidden-api-host-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-hidden-api-host{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Generate the stub/impl from framework-all, with only public/system/test APIs, without
+// hidden APIs.
+java_genrule_host {
+    name: "framework-all-test-api-host",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--intersect-stub-jar $(location :android_test_stubs_current{.jar}) " +
+        "--in-jar $(location :framework-all) " +
+        "--policy-override-file $(location framework-policy-override.txt) ",
+    srcs: [
+        ":framework-all",
+        ":android_test_stubs_current{.jar}",
+        "framework-policy-override.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Extract the stub jar from "framework-all-test-api-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-test-api-host-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-test-api-host{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Extract the impl jar from "framework-all-test-api-host" for subsequent build rules.
+java_genrule_host {
+    name: "framework-all-test-api-host-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":framework-all-test-api-host{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// This library contains helper classes to build hostside tests/targets.
+// This essentially contains dependencies from tests that we can't actually use the real ones.
+// For example, the actual AndroidTestCase and AndroidJUnit4 don't run on the host side (yet),
+// so we pup "fake" implementations here.
+// Ideally this library should be empty.
+java_library_host {
+    name: "hoststubgen-helper-framework-buildtime",
+    srcs: [
+        "helper-framework-buildtime-src/**/*.java",
+    ],
+    libs: [
+        // We need it to pull in some of the framework classes used in this library,
+        // such as Context.java.
+        "framework-all-hidden-api-host-impl",
+        "junit",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// This module contains "fake" libcore/dalvik classes, framework native substitution, etc,
+// that are needed at runtime.
+java_library_host {
+    name: "hoststubgen-helper-framework-runtime",
+    srcs: [
+        "helper-framework-runtime-src/**/*.java",
+    ],
+    libs: [
+        "hoststubgen-helper-runtime",
+        "framework-all-hidden-api-host-impl",
+    ],
+    visibility: ["//visibility:public"],
+}
+
+// Defaults for host side test modules.
+// We need two rules for each test.
+// 1. A "-test-lib" jar, which compiles the test against the stub jar.
+//    This one is only used by the second rule, so it should be "private.
+// 2. A "-test" jar, which includes 1 + the runtime (impl) jars.
+
+// This and next ones are for tests using framework-app, with hidden APIs.
+java_defaults {
+    name: "hosttest-with-framework-all-hidden-api-test-lib-defaults",
+    installable: false,
+    libs: [
+        "framework-all-hidden-api-host-stub",
+    ],
+    static_libs: [
+        "hoststubgen-helper-framework-buildtime",
+        "framework-annotations-lib",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Default rules to include `libandroid_runtime`. For now, it's empty, but we'll use it
+// once we start using JNI.
+java_defaults {
+    name: "hosttest-with-libandroid_runtime",
+    jni_libs: [
+        // "libandroid_runtime",
+
+        // TODO: Figure out how to build them automatically.
+        // Following ones are depended by libandroid_runtime.
+        // Without listing them here, not only we won't get them under
+        // $ANDROID_HOST_OUT/testcases/*/lib64, but also not under
+        // $ANDROID_HOST_OUT/lib64, so we'd fail to load them at runtime.
+        // ($ANDROID_HOST_OUT/lib/ gets all of them though.)
+        // "libcutils",
+        // "libharfbuzz_ng",
+        // "libminikin",
+        // "libz",
+        // "libbinder",
+        // "libhidlbase",
+        // "libvintf",
+        // "libicu",
+        // "libutils",
+        // "libtinyxml2",
+    ],
+}
+
+java_defaults {
+    name: "hosttest-with-framework-all-hidden-api-test-defaults",
+    defaults: ["hosttest-with-libandroid_runtime"],
+    installable: false,
+    test_config: "AndroidTest-host.xml",
+    static_libs: [
+        "hoststubgen-helper-runtime",
+        "hoststubgen-helper-framework-runtime",
+        "framework-all-hidden-api-host-impl",
+    ],
+}
+
+// This and next ones are for tests using framework-app, with public/system/test APIs,
+// without hidden APIs.
+java_defaults {
+    name: "hosttest-with-framework-all-test-api-test-lib-defaults",
+    installable: false,
+    libs: [
+        "framework-all-test-api-host-stub",
+    ],
+    static_libs: [
+        "hoststubgen-helper-framework-buildtime",
+        "framework-annotations-lib",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_defaults {
+    name: "hosttest-with-framework-all-test-api-test-defaults",
+    defaults: ["hosttest-with-libandroid_runtime"],
+    installable: false,
+    test_config: "AndroidTest-host.xml",
+    static_libs: [
+        "hoststubgen-helper-runtime",
+        "hoststubgen-helper-framework-runtime",
+        "framework-all-test-api-host-impl",
+    ],
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
new file mode 100644
index 0000000..a774336
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestClassLoadHook.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Add this with a fully-specified method name (e.g. {@code "com.package.Class.methodName"})
+ * of a callback to get a callback at the class load time.
+ *
+ * The method must be {@code public static} with a single argument that takes
+ * {@link java.lang.Class}.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestClassLoadHook {
+    String value();
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
new file mode 100644
index 0000000..06ad1c2
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestKeep.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Mark a class, field or a method as "Stub", meaning tests can _not_ see the APIs, but they
+ * can indirectly be used on the host side.
+ * When applied to a class, it will _not_ affect the visibility of its members. They need to be
+ * individually marked.
+ *
+ * <p>In order to expose a class and all its members, use {@link HostSideTestWholeClassStub}
+ * instead.
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestKeep {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java
new file mode 100644
index 0000000..9c81383
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * If a class has this annotation, all its native methods will be delegated to another class.
+ * (See {@link android.os.Parcel} as an example.)
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestNativeSubstitutionClass {
+    String value();
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
new file mode 100644
index 0000000..46e5078
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRemove.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Mark an item as "remove", so this cannot be used on the host side even indirectly.
+ * This is the default behavior.
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestRemove {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStub.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStub.java
new file mode 100644
index 0000000..cabdfe0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestStub.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Mark a class, field or a method as "Stub", meaning tests can see the APIs.
+ * When applied to a class, it will _not_ affect the visibility of its members. They need to be
+ * individually marked.
+ *
+ * <p>In order to expose a class and all its members, use {@link HostSideTestWholeClassStub}
+ * instead.
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestStub {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
new file mode 100644
index 0000000..510a67e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestSubstitute.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * If a method has this annotation, we'll replace it with another method on the host side.
+ *
+ * See {@link android.util.LruCache#getEldest()} and its substitution.
+ *
+ * @hide
+ */
+@Target({METHOD})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestSubstitute {
+    // TODO We should add "_host" as default. We're not doing it yet, because extractign the default
+    // value with ASM doesn't seem trivial. (? not sure.)
+    String suffix();
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
new file mode 100644
index 0000000..cd1bef4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestThrow.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * If a method has this annotation, it will throw on the host side.
+ *
+ * @hide
+ */
+@Target({METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestThrow {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
new file mode 100644
index 0000000..3d1ddea
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassKeep.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Same as {@link HostSideTestKeep} but it'll change the visibility of all its members too.
+ * @hide
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestWholeClassKeep {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassStub.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassStub.java
new file mode 100644
index 0000000..1824f6f
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestWholeClassStub.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
+ * QUESTIONS ABOUT IT.
+ *
+ * Same as {@link HostSideTestStub} but it'll change the visibility of all its members too.
+ *
+ * @hide
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface HostSideTestWholeClassStub {
+}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
new file mode 100644
index 0000000..b10f0ff
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/tests/HostSideTestSuppress.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hosttest.annotation.tests;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Target;
+
+/**
+ * Use this annotation to skip certain tests for host side tests.
+ *
+ * TODO: Actually use it in the test runner.
+ */
+@Target({TYPE, FIELD, METHOD})
+public @interface HostSideTestSuppress {
+}
diff --git a/tools/hoststubgen/hoststubgen/framework-policy-override.txt b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
new file mode 100644
index 0000000..295498d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/framework-policy-override.txt
@@ -0,0 +1,98 @@
+# --------------------------------------------------------------------------------------------------
+# This file contains rules to process `framework-all.jar` to generate the host side test "stub" and
+# "impl" jars, without using Java annotations.
+#
+# Useful when:
+# - The class is auto-generated and annotations can't be added.
+#   (We need to figure out what to do on auto-generated classes.)
+# - Want to quickly change filter rules without having to rebuild framework.jar.
+#
+# Using this file, one can control the visibility of APIs on a per-class, per-field and per-method
+# basis, but in most cases, per-class directives would be sufficient. That is:
+#
+# - To put the entire class, including its members and nested classes, in the "stub" jar,
+#   so that the test / target code can use the API, use `stubclass`.
+#
+# class package.class	stubclass
+#
+# - To put the entire class, including its members and nested classes, in the "impl" jar,
+#   but not in the "stub" jar, use `keepclass`. Use this when you don't want to expose an API to
+#   tests/target directly, but it's still needed at runtime, because it's used by other "stub" APIs
+#   directly or indirectly.
+#
+# class package.class	keepclass
+#
+# All other classes will be removed from both the stub jar and impl jar.
+#
+# --------------------------------------------------------------------------------------------------
+
+# --------------------------------------------------------------------------------------------------
+# Directions on auto-generated classes, where we can't use Java annotations (yet).
+# --------------------------------------------------------------------------------------------------
+class android.Manifest stubclass
+class android.R        stubclass
+class android.os.PersistableBundleProto	keepclass
+
+# This is in module-utils, where using a HostStubGen annotation would be complicated, so we
+# add a direction here rather than using a java annotation.
+# The build file says it's deprecated, anyway...? Figure out what to do with it.
+class com.android.internal.util.Preconditions keepclass
+
+# --------------------------------------------------------------------------------------------------
+# Actual framework classes
+# --------------------------------------------------------------------------------------------------
+
+# Put basic exception classes in the "impl" jar.
+# We don't put them in stub yet (until something actually needs them).
+class android.os.DeadObjectException          keepclass
+class android.os.DeadSystemRuntimeException   keepclass
+class android.os.NetworkOnMainThreadException keepclass
+class android.os.RemoteException              keepclass
+class android.os.ServiceSpecificException     keepclass
+class android.util.AndroidException           keepclass
+class android.util.AndroidRuntimeException    keepclass
+class android.os.DeadSystemException          keepclass
+
+
+# For now, we only want to expose ArrayMap and Log, but they and their tests depend on
+# more classes.
+
+class android.util.ArrayMap             stubclass
+
+# Used by ArrayMap. No need to put them in the stub, but we need them in impl.
+class android.util.MapCollections         keepclass
+class android.util.ContainerHelpers       keepclass
+class com.android.internal.util.XmlUtils  keepclass
+class com.android.internal.util.FastMath  keepclass
+class android.util.MathUtils              keepclass
+
+
+class android.util.Log          stubclass
+class android.util.Slog         stubclass
+# We don't use Log's native code, yet. Instead, the following line enables the Java substitution.
+# Comment it out to disable Java substitution of Log's native methods.
+class android.util.Log	!com.android.hoststubgen.nativesubstitution.Log_host
+
+# Used by log
+class com.android.internal.util.FastPrintWriter         keepclass
+class com.android.internal.util.LineBreakBufferedWriter keepclass
+
+
+# Expose Context because it's referred to by AndroidTestCase, but don't need to expose any of
+# its members.
+class android.content.Context        keep
+
+# Expose Parcel, Parcel and there relevant classes, which are used by ArrayMapTets.
+class android.os.Parcelable     StubClass
+class android.os.Parcel         StubClass
+class android.os.Parcel         !com.android.hoststubgen.nativesubstitution.Parcel_host
+
+class android.os.IBinder        stubClass
+class android.os.IInterface     stubclass
+
+class android.os.BadParcelableException     stubclass
+class android.os.BadTypeParcelableException stubclass
+
+class android.os.BaseBundle        stubclass
+class android.os.Bundle            stubclass
+class android.os.PersistableBundle stubclass
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/android/test/AndroidTestCase.java
similarity index 67%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/android/test/AndroidTestCase.java
index 24064b1..e6d3866 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/android/test/AndroidTestCase.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.test;
 
-package com.android.systemui.scene.ui.composable
+import android.content.Context;
 
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
+import junit.framework.TestCase;
 
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+public class AndroidTestCase extends TestCase {
+    protected Context mContext;
+    public Context getContext() {
+        throw new RuntimeException("[ravenwood] Class Context is not supported yet.");
+    }
 }
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/NonNull.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/NonNull.java
new file mode 100644
index 0000000..51c5d9a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/NonNull.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.annotation;
+
+// [ravenwood] TODO: Find the actual androidx jar containing it.s
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that a parameter, field or method return value can never be null.
+ * <p>
+ * This is a marker annotation and it has no specific attributes.
+ *
+ * @paramDoc This value cannot be {@code null}.
+ * @returnDoc This value cannot be {@code null}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface NonNull {
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/Nullable.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/Nullable.java
new file mode 100644
index 0000000..f1f0e8b
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/annotation/Nullable.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.annotation;
+
+// [ravenwood] TODO: Find the actual androidx jar containing it.s
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that a parameter, field or method return value can be null.
+ * <p>
+ * When decorating a method call parameter, this denotes that the parameter can
+ * legitimately be null and the method will gracefully deal with it. Typically
+ * used on optional parameters.
+ * <p>
+ * When decorating a method, this denotes the method might legitimately return
+ * null.
+ * <p>
+ * This is a marker annotation and it has no specific attributes.
+ *
+ * @paramDoc This value may be {@code null}.
+ * @returnDoc This value may be {@code null}.
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface Nullable {
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/ext/junit/runners/AndroidJUnit4.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/ext/junit/runners/AndroidJUnit4.java
new file mode 100644
index 0000000..0c82e4e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/ext/junit/runners/AndroidJUnit4.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.test.ext.junit.runners;
+
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+
+// TODO: We need to simulate the androidx test runner.
+// https://source.corp.google.com/piper///depot/google3/third_party/android/androidx_test/ext/junit/java/androidx/test/ext/junit/runners/AndroidJUnit4.java
+// https://source.corp.google.com/piper///depot/google3/third_party/android/androidx_test/runner/android_junit_runner/java/androidx/test/internal/runner/junit4/AndroidJUnit4ClassRunner.java
+
+public class AndroidJUnit4 extends BlockJUnit4ClassRunner {
+    public AndroidJUnit4(Class<?> testClass) throws InitializationError {
+        super(testClass);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/FlakyTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/FlakyTest.java
new file mode 100644
index 0000000..2470d839
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/FlakyTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Designates a test as being flaky (non-deterministic).
+ *
+ * <p>Can then be used to filter tests on execution using -e annotation or -e notAnnotation as
+ * desired.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface FlakyTest {
+  /**
+   * An optional bug number associated with the test. -1 Means that no bug number is associated with
+   * the flaky annotation.
+   *
+   * @return int
+   */
+  int bugId() default -1;
+
+  /**
+   * Details, such as the reason of why the test is flaky.
+   *
+   * @return String
+   */
+  String detail() default "";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/LargeTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/LargeTest.java
new file mode 100644
index 0000000..578d7dc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/LargeTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to assign a large test size qualifier to a test. This annotation can be used at a
+ * method or class level.
+ *
+ * <p>Test size qualifiers are a great way to structure test code and are used to assign a test to a
+ * test suite of similar run time.
+ *
+ * <p>Execution time: &gt;1000ms
+ *
+ * <p>Large tests should be focused on testing integration of all application components. These
+ * tests fully participate in the system and may make use of all resources such as databases, file
+ * systems and network. As a rule of thumb most functional UI tests are large tests.
+ *
+ * <p>Note: This class replaces the deprecated Android platform size qualifier <a
+ * href="{@docRoot}reference/android/test/suitebuilder/annotation/LargeTest.html"><code>
+ * android.test.suitebuilder.annotation.LargeTest</code></a> and is the recommended way to annotate
+ * tests written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface LargeTest {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/MediumTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/MediumTest.java
new file mode 100644
index 0000000..dfdaa53
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/MediumTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to assign a medium test size qualifier to a test. This annotation can be used at a
+ * method or class level.
+ *
+ * <p>Test size qualifiers are a great way to structure test code and are used to assign a test to a
+ * test suite of similar run time.
+ *
+ * <p>Execution time: &lt;1000ms
+ *
+ * <p>Medium tests should be focused on a very limited subset of components or a single component.
+ * Resource access to the file system through well defined interfaces like databases,
+ * ContentProviders, or Context is permitted. Network access should be restricted, (long-running)
+ * blocking operations should be avoided and use mock objects instead.
+ *
+ * <p>Note: This class replaces the deprecated Android platform size qualifier <a
+ * href="{@docRoot}reference/android/test/suitebuilder/annotation/MediumTest.html"><code>
+ * android.test.suitebuilder.annotation.MediumTest</code></a> and is the recommended way to annotate
+ * tests written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface MediumTest {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/RequiresDevice.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/RequiresDevice.java
new file mode 100644
index 0000000..3d3ee33
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/RequiresDevice.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a specific test should not be run on emulator.
+ *
+ * <p>It will be executed only if the test is running on the physical android device.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface RequiresDevice {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SdkSuppress.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SdkSuppress.java
new file mode 100644
index 0000000..dd65ddb
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SdkSuppress.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that a specific test or class requires a minimum or maximum API Level to execute.
+ *
+ * <p>Test(s) will be skipped when executed on android platforms less/more than specified level
+ * (inclusive).
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface SdkSuppress {
+  /** The minimum API level to execute (inclusive) */
+  int minSdkVersion() default 1;
+  /** The maximum API level to execute (inclusive) */
+  int maxSdkVersion() default Integer.MAX_VALUE;
+  /**
+   * The {@link android.os.Build.VERSION.CODENAME} to execute on. This is intended to be used to run
+   * on a pre-release SDK, where the {@link android.os.Build.VERSION.SDK_INT} has not yet been
+   * finalized. This is treated as an OR operation with respect to the minSdkVersion and
+   * maxSdkVersion attributes.
+   *
+   * <p>For example, to filter a test so it runs on only the prerelease R SDK: <code>
+   * {@literal @}SdkSuppress(minSdkVersion = Build.VERSION_CODES.R, codeName = "R")
+   * </code>
+   */
+  String codeName() default "unset";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SmallTest.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SmallTest.java
new file mode 100644
index 0000000..dd32df4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/SmallTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to assign a small test size qualifier to a test. This annotation can be used at a
+ * method or class level.
+ *
+ * <p>Test size qualifiers are a great way to structure test code and are used to assign a test to a
+ * test suite of similar run time.
+ *
+ * <p>Execution time: &lt;200ms
+ *
+ * <p>Small tests should be run very frequently. Focused on units of code to verify specific logical
+ * conditions. These tests should runs in an isolated environment and use mock objects for external
+ * dependencies. Resource access (such as file system, network, or databases) are not permitted.
+ * Tests that interact with hardware, make binder calls, or that facilitate android instrumentation
+ * should not use this annotation.
+ *
+ * <p>Note: This class replaces the deprecated Android platform size qualifier <a
+ * href="http://developer.android.com/reference/android/test/suitebuilder/annotation/SmallTest.html">
+ * android.test.suitebuilder.annotation.SmallTest</a> and is the recommended way to annotate tests
+ * written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SmallTest {}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/Suppress.java b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/Suppress.java
new file mode 100644
index 0000000..88e636c
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/filters/Suppress.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.test.filters;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Use this annotation on test classes or test methods that should not be included in a test suite.
+ * If the annotation appears on the class then no tests in that class will be included. If the
+ * annotation appears only on a test method then only that method will be excluded.
+ *
+ * <p>Note: This class replaces the deprecated Android platform annotation <a
+ * href="http://developer.android.com/reference/android/test/suitebuilder/annotation/Suppress.html">
+ * android.test.suitebuilder.annotation.Suppress</a> and is the recommended way to suppress tests
+ * written with the AndroidX Test Library.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Suppress {}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/runner/AndroidJUnit4.java
similarity index 63%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/runner/AndroidJUnit4.java
index 24064b1..e137939 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/tools/hoststubgen/hoststubgen/helper-framework-buildtime-src/androidx/test/runner/AndroidJUnit4.java
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,14 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.test.runner;
 
-package com.android.systemui.scene.ui.composable
+import org.junit.runners.model.InitializationError;
 
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
-
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+public class AndroidJUnit4 extends androidx.test.ext.junit.runners.AndroidJUnit4 {
+    public AndroidJUnit4(Class<?> testClass) throws InitializationError {
+        super(testClass);
+    }
 }
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
new file mode 100644
index 0000000..ee55c7a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Log_host.java
@@ -0,0 +1,61 @@
+/*
+ * 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.hoststubgen.nativesubstitution;
+
+import android.util.Log;
+import android.util.Log.Level;
+
+import java.io.PrintStream;
+
+public class Log_host {
+
+    public static boolean isLoggable(String tag, @Level int level) {
+        return true;
+    }
+
+    public static int println_native(int bufID, int priority, String tag, String msg) {
+        final PrintStream out = System.out;
+        final String buffer;
+        switch (bufID) {
+            case Log.LOG_ID_MAIN: buffer = "main"; break;
+            case Log.LOG_ID_RADIO: buffer = "radio"; break;
+            case Log.LOG_ID_EVENTS: buffer = "event"; break;
+            case Log.LOG_ID_SYSTEM: buffer = "system"; break;
+            case Log.LOG_ID_CRASH: buffer = "crash"; break;
+            default: buffer = "buf:" + bufID; break;
+        };
+
+        final String prio;
+        switch (priority) {
+            case Log.VERBOSE: prio = "V"; break;
+            case Log.DEBUG: prio = "D"; break;
+            case Log.INFO: prio = "I"; break;
+            case Log.WARN: prio = "W"; break;
+            case Log.ERROR: prio = "E"; break;
+            case Log.ASSERT: prio = "A"; break;
+            default: prio = "prio:" + priority; break;
+        };
+
+        for (String s : msg.split("\\n")) {
+            out.println(String.format("logd: [%s] %s %s: %s", buffer, prio, tag, s));
+        }
+        return msg.length();
+    }
+
+    public static int logger_entry_max_payload_native() {
+        return 4068; // [ravenwood] This is what people use in various places.
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
new file mode 100644
index 0000000..d749f07
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/Parcel_host.java
@@ -0,0 +1,404 @@
+/*
+ * 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.hoststubgen.nativesubstitution;
+
+import android.os.IBinder;
+
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Tentative, partial implementation of the Parcel native methods, using Java's
+ * {@link ByteBuffer}. It turned out there's enough semantics differences between Parcel
+ * and {@link ByteBuffer}, so it didn't actually work.
+ * (e.g. Parcel seems to allow moving the data position to be beyond its size? Which
+ * {@link ByteBuffer} wouldn't allow...)
+ */
+public class Parcel_host {
+    private Parcel_host() {
+    }
+
+    private static final AtomicLong sNextId = new AtomicLong(0);
+
+    private static final Map<Long, Parcel_host> sInstances = new ConcurrentHashMap<>();
+
+    private boolean mDeleted = false;
+
+    private byte[] mBuffer;
+    private int mSize;
+    private int mPos;
+
+    private boolean mSensitive;
+    private boolean mAllowFds;
+
+    // TODO Use the actual value from Parcel.java.
+    private static final int OK = 0;
+
+    private void validate() {
+        if (mDeleted) {
+            // TODO: Put more info
+            throw new RuntimeException("Parcel already destroyed");
+        }
+    }
+
+    private static Parcel_host getInstance(long id) {
+        Parcel_host p = sInstances.get(id);
+        if (p == null) {
+            // TODO: Put more info
+            throw new RuntimeException("Parcel doesn't exist with id=" + id);
+        }
+        p.validate();
+        return p;
+    }
+
+    public static long nativeCreate() {
+        final long id = sNextId.getAndIncrement();
+        final Parcel_host p = new Parcel_host();
+        sInstances.put(id, p);
+        p.init();
+        return id;
+    }
+
+    private void init() {
+        mBuffer = new byte[0];
+        mSize = 0;
+        mPos = 0;
+        mSensitive = false;
+        mAllowFds = false;
+    }
+
+    private void updateSize() {
+        if (mSize < mPos) {
+            mSize = mPos;
+        }
+    }
+
+    public static void nativeDestroy(long nativePtr) {
+        getInstance(nativePtr).mDeleted = true;
+        sInstances.remove(nativePtr);
+    }
+
+    public static void nativeFreeBuffer(long nativePtr) {
+        getInstance(nativePtr).freeBuffer();
+    }
+
+    public void freeBuffer() {
+        init();
+    }
+
+    private int getCapacity() {
+        return mBuffer.length;
+    }
+
+    private void ensureMoreCapacity(int size) {
+        ensureCapacity(mPos + size);
+    }
+
+    private void ensureCapacity(int targetSize) {
+        if (targetSize <= getCapacity()) {
+            return;
+        }
+        var newSize = getCapacity() * 2;
+        if (newSize < targetSize) {
+            newSize = targetSize;
+        }
+        forceSetCapacity(newSize);
+    }
+
+    private void forceSetCapacity(int newSize) {
+        var newBuf = new byte[newSize];
+
+        // Copy
+        System.arraycopy(mBuffer, 0, newBuf, 0, Math.min(newSize, getCapacity()));
+
+        this.mBuffer = newBuf;
+    }
+
+    private void ensureDataAvailable(int requestSize) {
+        if (mSize - mPos < requestSize) {
+            throw new RuntimeException(String.format(
+                    "Pacel data underflow. size=%d, pos=%d, request=%d", mSize, mPos, requestSize));
+        }
+    }
+
+    public static void nativeMarkSensitive(long nativePtr) {
+        getInstance(nativePtr).mSensitive = true;
+    }
+    public static void nativeMarkForBinder(long nativePtr, IBinder binder) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean nativeIsForRpc(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int nativeDataSize(long nativePtr) {
+        return getInstance(nativePtr).mSize;
+    }
+    public static int nativeDataAvail(long nativePtr) {
+        var p = getInstance(nativePtr);
+        return p.mSize - p.mPos;
+    }
+    public static int nativeDataPosition(long nativePtr) {
+        return getInstance(nativePtr).mPos;
+    }
+    public static int nativeDataCapacity(long nativePtr) {
+        return getInstance(nativePtr).mBuffer.length;
+    }
+    public static void nativeSetDataSize(long nativePtr, int size) {
+        var p = getInstance(nativePtr);
+        p.ensureCapacity(size);
+        getInstance(nativePtr).mSize = size;
+    }
+    public static void nativeSetDataPosition(long nativePtr, int pos) {
+        var p = getInstance(nativePtr);
+        // TODO: Should this change the size or the capacity??
+        p.mPos = pos;
+    }
+    public static void nativeSetDataCapacity(long nativePtr, int size) {
+        var p = getInstance(nativePtr);
+        if (p.getCapacity() < size) {
+            p.forceSetCapacity(size);
+        }
+    }
+
+    public static boolean nativePushAllowFds(long nativePtr, boolean allowFds) {
+        var p = getInstance(nativePtr);
+        var prev = p.mAllowFds;
+        p.mAllowFds = allowFds;
+        return prev;
+    }
+    public static void nativeRestoreAllowFds(long nativePtr, boolean lastValue) {
+        getInstance(nativePtr).mAllowFds = lastValue;
+    }
+
+    public static void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len) {
+        nativeWriteBlob(nativePtr, b, offset, len);
+    }
+
+    public static void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len) {
+        var p = getInstance(nativePtr);
+
+        if (b == null) {
+            nativeWriteInt(nativePtr, -1);
+        } else {
+            final var alignedSize = align4(b.length);
+
+            nativeWriteInt(nativePtr, b.length);
+
+            p.ensureMoreCapacity(alignedSize);
+
+            System.arraycopy(b, offset, p.mBuffer,  p.mPos, len);
+            p.mPos += alignedSize;
+            p.updateSize();
+        }
+    }
+
+    public static int nativeWriteInt(long nativePtr, int value) {
+        var p = getInstance(nativePtr);
+        p.ensureMoreCapacity(Integer.BYTES);
+
+        p.mBuffer[p.mPos++] = (byte) ((value >> 24) & 0xff);
+        p.mBuffer[p.mPos++] = (byte) ((value >> 16) & 0xff);
+        p.mBuffer[p.mPos++] = (byte) ((value >>  8) & 0xff);
+        p.mBuffer[p.mPos++] = (byte) ((value >>  0) & 0xff);
+
+        p.updateSize();
+
+        return OK;
+    }
+
+    public static int nativeWriteLong(long nativePtr, long value) {
+        nativeWriteInt(nativePtr, (int) (value >>> 32));
+        nativeWriteInt(nativePtr, (int) (value));
+        return OK;
+    }
+    public static int nativeWriteFloat(long nativePtr, float val) {
+        return nativeWriteInt(nativePtr, Float.floatToIntBits(val));
+    }
+    public static int nativeWriteDouble(long nativePtr, double val) {
+        return nativeWriteLong(nativePtr, Double.doubleToLongBits(val));
+    }
+    public static void nativeSignalExceptionForError(int error) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    private static int align4(int val) {
+        return ((val + 3) / 4) * 4;
+    }
+
+    public static void nativeWriteString8(long nativePtr, String val) {
+        if (val == null) {
+            nativeWriteBlob(nativePtr, null, 0, 0);
+        } else {
+            var bytes = val.getBytes(StandardCharsets.UTF_8);
+            nativeWriteBlob(nativePtr, bytes, 0, bytes.length);
+        }
+    }
+    public static void nativeWriteString16(long nativePtr, String val) {
+        // Just reuse String8
+        nativeWriteString8(nativePtr, val);
+    }
+    public static void nativeWriteStrongBinder(long nativePtr, IBinder val) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static byte[] nativeCreateByteArray(long nativePtr) {
+        return nativeReadBlob(nativePtr);
+    }
+
+    public static boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen) {
+        if (dest == null) {
+            return false;
+        }
+        var data = nativeReadBlob(nativePtr);
+        if (data == null) {
+            System.err.println("Percel has NULL, which is unexpected."); // TODO: Is this correct?
+            return false;
+        }
+        // TODO: Make sure the check logic is correct.
+        if (data.length != destLen) {
+            System.err.println("Byte array size mismatch: expected="
+                    + data.length + " given=" + destLen);
+            return false;
+        }
+        return true;
+    }
+
+    public static byte[] nativeReadBlob(long nativePtr) {
+        final var size = nativeReadInt(nativePtr);
+        if (size == -1) {
+            return null;
+        }
+        var p = getInstance(nativePtr);
+        p.ensureDataAvailable(size);
+
+        var bytes = new byte[size];
+        System.arraycopy(p.mBuffer, p.mPos, bytes, 0, size);
+
+        p.mPos += align4(size);
+
+        return bytes;
+    }
+    public static int nativeReadInt(long nativePtr) {
+        var p = getInstance(nativePtr);
+
+        p.ensureDataAvailable(Integer.BYTES);
+
+        var ret = (((p.mBuffer[p.mPos++] & 0xff) << 24)
+                | ((p.mBuffer[p.mPos++] & 0xff) << 16)
+                | ((p.mBuffer[p.mPos++] & 0xff) <<  8)
+                | ((p.mBuffer[p.mPos++] & 0xff) <<  0));
+
+        return ret;
+    }
+    public static long nativeReadLong(long nativePtr) {
+        return (((long) nativeReadInt(nativePtr)) << 32)
+                | (((long) nativeReadInt(nativePtr)) & 0xffff_ffffL);
+    }
+
+    public static float nativeReadFloat(long nativePtr) {
+        return Float.intBitsToFloat(nativeReadInt(nativePtr));
+    }
+
+    public static double nativeReadDouble(long nativePtr) {
+        return Double.longBitsToDouble(nativeReadLong(nativePtr));
+    }
+
+    public static String nativeReadString8(long nativePtr) {
+        final var bytes = nativeReadBlob(nativePtr);
+        if (bytes == null) {
+            return null;
+        }
+        return new String(bytes, StandardCharsets.UTF_8);
+    }
+    public static String nativeReadString16(long nativePtr) {
+        return nativeReadString8(nativePtr);
+    }
+    public static IBinder nativeReadStrongBinder(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static FileDescriptor nativeReadFileDescriptor(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static byte[] nativeMarshall(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeUnmarshall(
+            long nativePtr, byte[] data, int offset, int length) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int nativeCompareData(long thisNativePtr, long otherNativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean nativeCompareDataInRange(
+            long ptrA, int offsetA, long ptrB, int offsetB, int length) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeAppendFrom(
+            long thisNativePtr, long otherNativePtr, int srcOffset, int length) {
+        var dst = getInstance(thisNativePtr);
+        var src = getInstance(otherNativePtr);
+
+        dst.ensureMoreCapacity(length);
+
+        System.arraycopy(src.mBuffer, srcOffset, dst.mBuffer, dst.mPos, length);
+        dst.mPos += length; // TODO: 4 byte align?
+        dst.updateSize();
+
+        // TODO: Update the other's position?
+    }
+
+    public static boolean nativeHasFileDescriptors(long nativePtr) {
+        // Assume false for now, because we don't support writing FDs yet.
+        return false;
+    }
+    public static boolean nativeHasFileDescriptorsInRange(
+            long nativePtr, int offset, int length) {
+        // Assume false for now, because we don't support writing FDs yet.
+        return false;
+    }
+    public static void nativeWriteInterfaceToken(long nativePtr, String interfaceName) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void nativeEnforceInterface(long nativePtr, String interfaceName) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static boolean nativeReplaceCallingWorkSourceUid(
+            long nativePtr, int workSourceUid) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int nativeReadCallingWorkSourceUid(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static long nativeGetOpenAshmemSize(long nativePtr) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long getGlobalAllocSize() {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long getGlobalAllocCount() {
+        throw new RuntimeException("Not implemented yet");
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
new file mode 100644
index 0000000..1ec1d5f
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/SystemProperties_host.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.nativesubstitution;
+
+public class SystemProperties_host {
+    public static String native_get(String key, String def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int native_get_int(String key, int def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long native_get_long(String key, long def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean native_get_boolean(String key, boolean def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+
+    public static long native_find(String name) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static String native_get(long handle) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static int native_get_int(long handle, int def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static long native_get_long(long handle, long def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static boolean native_get_boolean(long handle, boolean def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void native_set(String key, String def) {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void native_add_change_callback() {
+        throw new RuntimeException("Not implemented yet");
+    }
+    public static void native_report_sysprop_change() {
+        throw new RuntimeException("Not implemented yet");
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
new file mode 100644
index 0000000..4c2d3c4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/runtimehelper/ClassLoadHook.java
@@ -0,0 +1,182 @@
+/*
+ * 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.hoststubgen.runtimehelper;
+
+import com.android.hoststubgen.hosthelper.HostTestException;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Standard class to handle class load hook.
+ *
+ * We use this to initialize the environment necessary for some classes. (e.g. load native libs.)
+ */
+public class ClassLoadHook {
+    private static PrintStream out = System.out;
+
+    /**
+     * If true, we won't load `libandroid_runtime`
+     *
+     * <p>Looks like there's some complexity in running a host test with JNI with `atest`,
+     * so we need a way to remove the dependency.
+     */
+    private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
+            "HOSTTEST_SKIP_LOADING_LIBANDROID"));
+
+    public static final String CORE_NATIVE_CLASSES = "core_native_classes";
+    public static final String ICU_DATA_PATH = "icu.data.path";
+    public static final String KEYBOARD_PATHS = "keyboard_paths";
+    public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes";
+
+    public static final String VALUE_N_A = "**n/a**";
+    public static final String LIBANDROID_RUNTIME_NAME = "libandroid_runtime";
+
+    private static String sInitialDir = new File("").getAbsolutePath();
+
+    static {
+        log("Initialized. Current dir=" + sInitialDir);
+    }
+
+    private ClassLoadHook() {
+    }
+
+    /**
+     * Called when classes with
+     * {@code @HostSideTestClassLoadHook("com.android.hoststubgen.runtimehelper.ClassLoadHook.onClassLoaded") }
+     * are loaded.
+     */
+    public static void onClassLoaded(Class<?> clazz) {
+        System.out.println("Framework class loaded: " + clazz.getCanonicalName());
+
+        if (android.util.Log.class == clazz) {
+            loadFrameworkNativeCode();
+        }
+    }
+
+    private static void log(String message) {
+        out.println("ClassLoadHook: " + message);
+    }
+
+    private static void log(String fmt, Object... args) {
+        log(String.format(fmt, args));
+    }
+
+    private static void ensurePropertyNotSet(String key) {
+        if (System.getProperty(key) != null) {
+            throw new HostTestException("System property \"" + key + "\" is set unexpectedly");
+        }
+    }
+
+    private static void setProperty(String key, String value) {
+        System.setProperty(key, value);
+        log("Property set: %s=\"%s\"", key, value);
+    }
+
+    private static void dumpSystemProperties() {
+        for (var prop : System.getProperties().entrySet()) {
+            log("  %s=\"%s\"", prop.getKey(), prop.getValue());
+        }
+    }
+
+    private static void loadJniLibrary(String name) {
+        final String path = sInitialDir + "/lib64/" + name + ".so";
+        System.out.println("Loading " + path + " ...");
+        System.load(path);
+        System.out.println("Done loading " + path);
+    }
+
+    private static boolean sLoadFrameworkNativeCodeCalled = false;
+
+    /**
+     * Load `libandroid_runtime` if needed.
+     */
+    private static void loadFrameworkNativeCode() {
+        // This is called from class-initializers, so no synchronization is needed.
+        if (sLoadFrameworkNativeCodeCalled) {
+            // This method has already been called before.s
+            return;
+        }
+        sLoadFrameworkNativeCodeCalled = true;
+
+        // libandroid_runtime uses Java's system properties to decide what JNI methods to set up.
+        // Set up these properties for host-side tests.
+
+        if ("1".equals(System.getenv("HOSTTEST_DUMP_PROPERTIES"))) {
+            log("Java system properties:");
+            dumpSystemProperties();
+        }
+
+        if (SKIP_LOADING_LIBANDROID) {
+            log("Skip loading " + LIBANDROID_RUNTIME_NAME);
+        }
+
+        // Make sure these properties are not set.
+        ensurePropertyNotSet(CORE_NATIVE_CLASSES);
+        ensurePropertyNotSet(ICU_DATA_PATH);
+        ensurePropertyNotSet(KEYBOARD_PATHS);
+        ensurePropertyNotSet(GRAPHICS_NATIVE_CLASSES);
+
+        // Tell libandroid what JNI to use.
+        final var jniClasses = getCoreNativeClassesToUse();
+        if (jniClasses.isEmpty()) {
+            log("No classes require JNI methods, skip loading " + LIBANDROID_RUNTIME_NAME);
+            return;
+        }
+        setProperty(CORE_NATIVE_CLASSES, jniClasses);
+        setProperty(GRAPHICS_NATIVE_CLASSES, "");
+        setProperty(ICU_DATA_PATH, VALUE_N_A);
+        setProperty(KEYBOARD_PATHS, VALUE_N_A);
+
+        loadJniLibrary(LIBANDROID_RUNTIME_NAME);
+    }
+
+    /**
+     * @return if a given method is a native method or not.
+     */
+    private static boolean isNativeMethod(Class<?> clazz, String methodName, Class<?>... argTypes) {
+        try {
+            final var method = clazz.getMethod(methodName, argTypes);
+            return Modifier.isNative(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            throw new HostTestException(String.format(
+                    "Class %s doesn't have method %s with args %s",
+                    clazz.getCanonicalName(),
+                    methodName,
+                    Arrays.toString(argTypes)), e);
+        }
+    }
+
+    /**
+     * Create a list of classes as comma-separated that require JNI methods to be set up.
+     *
+     * <p>This list is used by frameworks/base/core/jni/LayoutlibLoader.cpp to decide
+     * what JNI methods to set up.
+     */
+    private static String getCoreNativeClassesToUse() {
+        final var coreNativeClassesToLoad = new ArrayList<String>();
+
+        if (isNativeMethod(android.util.Log.class, "isLoggable",
+                String.class, int.class)) {
+            coreNativeClassesToLoad.add("android.util.Log");
+        }
+
+        return String.join(",", coreNativeClassesToLoad);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java
new file mode 100644
index 0000000..7d2b00d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/dalvik/system/VMRuntime.java
@@ -0,0 +1,45 @@
+/*
+ * 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 dalvik.system;
+
+// [ravenwood] It's in libart, so until we get ART to work, we need to use a fake.
+// The original is here:
+// $ANDROID_BUILD_TOP/libcore/libart/src/main/java/dalvik/system/VMRuntime.java
+
+import java.lang.reflect.Array;
+
+public class VMRuntime {
+    private static final VMRuntime THE_ONE = new VMRuntime();
+
+    private VMRuntime() {
+    }
+
+    public static VMRuntime getRuntime() {
+        return THE_ONE;
+    }
+
+    public boolean is64Bit() {
+        return true;
+    }
+
+    public static boolean is64BitAbi(String abi) {
+        return true;
+    }
+
+    public Object newUnpaddedArray(Class<?> componentType, int minLength) {
+        return Array.newInstance(componentType, minLength);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java
new file mode 100644
index 0000000..a1ae35a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/EmptyArray.java
@@ -0,0 +1,54 @@
+/*
+ * 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 libcore.util;
+
+import java.lang.annotation.Annotation;
+
+// [ravenwood] Copied from libcore. TODO: Figure out what to do with libcore.
+public class EmptyArray {
+    private EmptyArray() {}
+
+    public static final boolean[] BOOLEAN = new boolean[0];
+
+    public static final byte[] BYTE = new byte[0];
+
+    public static final char[] CHAR = new char[0];
+
+    public static final double[] DOUBLE = new double[0];
+
+    public static final float[] FLOAT = new float[0];
+
+    public static final int[] INT = new int[0];
+
+    public static final long[] LONG = new long[0];
+
+    public static final Class<?>[] CLASS = new Class[0];
+
+    public static final Object[] OBJECT = new Object[0];
+
+    public static final String[] STRING = new String[0];
+
+    public static final Throwable[] THROWABLE = new Throwable[0];
+
+    public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];
+
+    public static final java.lang.reflect.Type[] TYPE = new java.lang.reflect.Type[0];
+
+    public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE =
+            new java.lang.reflect.TypeVariable[0];
+    public static final Annotation[] ANNOTATION = new Annotation[0];
+
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java
new file mode 100644
index 0000000..e142c46
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/libcore-fake/libcore/util/SneakyThrow.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package libcore.util;
+
+// [ravenwood] Copied from libcore. TODO: Figure out what to do with libcore.
+
+public class SneakyThrow {
+
+    private SneakyThrow() {
+    }
+
+    public static void sneakyThrow(Throwable t) {
+        SneakyThrow.<RuntimeException>sneakyThrow_(t);
+    }
+
+    private static <T extends Throwable> void sneakyThrow_(Throwable t) throws T {
+       throw (T) t;
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java
new file mode 100644
index 0000000..4c37579
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedKeepClass.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.hosthelper;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import org.objectweb.asm.Type;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation added to all "stub" classes generated by HostStubGen.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostStubGenProcessedKeepClass {
+    String CLASS_INTERNAL_NAME = Type.getInternalName(HostStubGenProcessedKeepClass.class);
+    String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";";
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java
new file mode 100644
index 0000000..34e0030
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostStubGenProcessedStubClass.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.hosthelper;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import org.objectweb.asm.Type;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation added to all "stub" classes generated by HostStubGen.
+ */
+@Target({TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostStubGenProcessedStubClass {
+    String CLASS_INTERNAL_NAME = Type.getInternalName(HostStubGenProcessedStubClass.class);
+    String CLASS_DESCRIPTOR = "L" + CLASS_INTERNAL_NAME + ";";
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
similarity index 68%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
index 24064b1..c54c2c1 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestException.java
@@ -13,14 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.hoststubgen.hosthelper;
 
-package com.android.systemui.scene.ui.composable
+public class HostTestException extends RuntimeException {
+    public HostTestException(String message) {
+        super(message);
+    }
 
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
-
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
+    public HostTestException(String message, Throwable inner) {
+        super(message, inner);
+    }
 }
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
new file mode 100644
index 0000000..29f7be0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestSuite.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.hosthelper;
+
+import com.google.common.reflect.ClassPath;
+import com.google.common.reflect.ClassPath.ClassInfo;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.TestSuite;
+
+import java.util.regex.Pattern;
+
+/**
+ * A very simple Junit {@link TestSuite} builder that finds all classes that look like test classes.
+ *
+ * We use it to run ravenwood test jars from the command line.
+ */
+public class HostTestSuite {
+    private static final String CLASS_NAME_REGEX_ENV = "HOST_TEST_CLASS_NAME_REGEX";
+
+    /**
+     * Called by junit, and return all test-looking classes as a suite.
+     */
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite();
+
+        final Pattern classNamePattern;
+        final var filterRegex = System.getenv(CLASS_NAME_REGEX_ENV);
+        if (filterRegex == null) {
+            classNamePattern = Pattern.compile("");
+        } else {
+            classNamePattern = Pattern.compile(filterRegex);
+        }
+        try {
+            // We use guava to list all classes.
+            ClassPath cp = ClassPath.from(HostTestSuite.class.getClassLoader());
+
+            for (var classInfo : cp.getAllClasses()) {
+                Class<?> clazz = asTestClass(classInfo);
+                if (clazz != null) {
+                    if (classNamePattern.matcher(clazz.getSimpleName()).find()) {
+                        System.out.println("Test class found " + clazz.getName());
+                    } else {
+                        System.out.println("Skipping test class (for $"
+                                + CLASS_NAME_REGEX_ENV + "): " + clazz.getName());
+                    }
+                    suite.addTest(new JUnit4TestAdapter(clazz));
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return suite;
+    }
+
+    /**
+     * Decide whether a class looks like a test class or not, and if so, return it as a Class
+     * instance.
+     */
+    private static Class<?> asTestClass(ClassInfo classInfo) {
+        try {
+            final Class<?> clazz = classInfo.load();
+
+            // Does it extend junit.framework.TestCase?
+            if (junit.framework.TestCase.class.isAssignableFrom(clazz)) {
+                // Ignore classes in JUnit itself, or the android(x) test lib.
+                if (classInfo.getName().startsWith("junit.")
+                        || classInfo.getName().startsWith("org.junit.")
+                        || classInfo.getName().startsWith("android.test.")
+                        || classInfo.getName().startsWith("androidx.test.")) {
+                    return null; // Ignore junit classes.
+                }
+                return clazz;
+            }
+            // Does it have any "@Test" method?
+            for (var method : clazz.getMethods()) {
+                for (var an : method.getAnnotations()) {
+                    if (an.annotationType() == org.junit.Test.class) {
+                        return clazz;
+                    }
+                }
+            }
+            return null;
+        } catch (java.lang.NoClassDefFoundError e) {
+            // Ignore unloadable classes.
+            return null;
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
new file mode 100644
index 0000000..f7719a6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.hosthelper;
+
+import org.objectweb.asm.Type;
+
+import java.io.PrintStream;
+import java.lang.StackWalker.Option;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * Utilities used in the host side test environment.
+ */
+public class HostTestUtils {
+    private HostTestUtils() {
+    }
+
+    public static final String CLASS_INTERNAL_NAME = Type.getInternalName(HostTestUtils.class);
+
+    /** If true, we won't print method call log. */
+    private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv(
+            "HOSTTEST_SKIP_METHOD_LOG"));
+
+    /** If true, we won't perform non-stub method direct call check. */
+    private static final boolean SKIP_NON_STUB_METHOD_CHECK = "1".equals(System.getenv(
+            "HOSTTEST_SKIP_NON_STUB_METHOD_CHECK"));
+
+
+    /**
+     * Method call log will be printed to it.
+     */
+    public static PrintStream logPrintStream = System.out;
+
+    /**
+     * Called from methods with FilterPolicy.Throw.
+     */
+    public static void onThrowMethodCalled() {
+        // TODO: Maybe add call tracking?
+        throw new RuntimeException("This method is not supported on the host side");
+    }
+
+    /**
+     * Called from methods with FilterPolicy.Log.
+     */
+    public static void logMethodCall(
+            String methodClass,
+            String methodName,
+            String methodDescriptor
+    ) {
+        if (SKIP_METHOD_LOG) {
+            return;
+        }
+        logPrintStream.println("# " + methodClass + "." + methodName + methodDescriptor);
+    }
+
+    private static final StackWalker sStackWalker =
+            StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
+
+    /**
+     * Return a {@link StackWalker} that supports {@link StackWalker#getCallerClass()}.
+     */
+    public static StackWalker getStackWalker() {
+        return sStackWalker;
+    }
+
+    /**
+     * Cache used by {@link #isClassAllowedToCallNonStubMethods}.
+     */
+    @GuardedBy("sAllowedClasses")
+    private static final HashMap<Class, Boolean> sAllowedClasses = new HashMap();
+
+    /**
+     * Return true if a given class is allowed to access non-stub methods -- that is, if the class
+     * is in the hoststubgen generated JARs. (not in the test jar.)
+     */
+    private static boolean isClassAllowedToCallNonStubMethods(Class<?> clazz) {
+        synchronized (sAllowedClasses) {
+            var cached = sAllowedClasses.get(clazz);
+            if (cached != null) {
+                return cached;
+            }
+        }
+        // All processed classes have this annotation.
+        var allowed = clazz.getAnnotation(HostStubGenProcessedKeepClass.class) != null;
+
+        // Java classes should be able to access any methods. (via callbacks, etc.)
+        if (!allowed) {
+            if (clazz.getPackageName().startsWith("java.")
+                    || clazz.getPackageName().startsWith("javax.")) {
+                allowed = true;
+            }
+        }
+        synchronized (sAllowedClasses) {
+            sAllowedClasses.put(clazz, allowed);
+        }
+        return allowed;
+    }
+
+    /**
+     * Called when non-stub methods are called. We do a host-unsupported method direct call check
+     * in here.
+     */
+    public static void onNonStubMethodCalled(
+            String methodClass,
+            String methodName,
+            String methodDescriptor,
+            Class<?> callerClass) {
+        if (SKIP_NON_STUB_METHOD_CHECK) {
+            return;
+        }
+        if (isClassAllowedToCallNonStubMethods(callerClass)) {
+            return; // Generated class is allowed to call framework class.
+        }
+        logPrintStream.println("! " + methodClass + "." + methodName + methodDescriptor
+                + " called by " + callerClass.getCanonicalName());
+    }
+
+    /**
+     * Called when any top level class (not nested classes) in the impl jar is loaded.
+     *
+     * When HostStubGen inject a class-load hook, it's always a call to this method, with the
+     * actual method name as the second argument.
+     *
+     * This method discovers the hook method with reflections and call it.
+     *
+     * TODO: Add a unit test.
+     */
+    public static void onClassLoaded(Class<?> loadedClass, String callbackMethod) {
+        logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName()
+                + " calling hook " + callbackMethod);
+
+        // Forward the call to callbackMethod.
+        final int lastPeriod = callbackMethod.lastIndexOf(".");
+        final String className = callbackMethod.substring(0, lastPeriod);
+        final String methodName = callbackMethod.substring(lastPeriod + 1);
+
+        if (lastPeriod < 0 || className.isEmpty() || methodName.isEmpty()) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: malformed method name \"%s\"",
+                    callbackMethod));
+        }
+
+        Class<?> clazz = null;
+        try {
+            clazz = Class.forName(className);
+        } catch (Exception e) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: Class %s not found", className), e);
+        }
+        if (!Modifier.isPublic(clazz.getModifiers())) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: Class %s must be public", className));
+        }
+
+        Method method = null;
+        try {
+            method = clazz.getMethod(methodName, Class.class);
+        } catch (Exception e) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: class %s doesn't have method %s"
+                    + " (method must take exactly one parameter of type Class, and public static)",
+                    className,
+                    methodName), e);
+        }
+        if (!(Modifier.isPublic(method.getModifiers())
+                && Modifier.isStatic(method.getModifiers()))) {
+            throw new HostTestException(String.format(
+                    "Unable to find class load hook: Method %s in class %s must be public static",
+                    methodName, className));
+        }
+        try {
+            method.invoke(null, loadedClass);
+        } catch (Exception e) {
+            throw new HostTestException(String.format(
+                    "Unable to invoke class load hook %s.%s",
+                    className,
+                    methodName), e);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
new file mode 100644
index 0000000..828d2a3
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
@@ -0,0 +1,39 @@
+# File containing standard options to HostStubGen
+
+--debug
+
+# Uncomment below lines to enable each feature.
+--enable-non-stub-method-check
+# --no-non-stub-method-check
+
+# --enable-method-logging
+
+
+# Standard annotations.
+# Note, each line is a single argument, so we need newlines after each `--xxx-annotation`.
+--stub-annotation
+    android.hosttest.annotation.HostSideTestStub
+
+--keep-annotation
+    android.hosttest.annotation.HostSideTestKeep
+
+--stub-class-annotation
+    android.hosttest.annotation.HostSideTestWholeClassStub
+
+--keep-class-annotation
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+
+--throw-annotation
+    android.hosttest.annotation.HostSideTestThrow
+
+--remove-annotation
+    android.hosttest.annotation.HostSideTestRemove
+
+--substitute-annotation
+    android.hosttest.annotation.HostSideTestSubstitute
+
+--native-substitute-annotation
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass
+
+--class-load-hook-annotation
+    android.hosttest.annotation.HostSideTestClassLoadHook
diff --git a/tools/hoststubgen/hoststubgen/jarjar-rules.txt b/tools/hoststubgen/hoststubgen/jarjar-rules.txt
new file mode 100644
index 0000000..4e61ba6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/jarjar-rules.txt
@@ -0,0 +1,2 @@
+# Rename guava
+rule com.google.common.** com.android.hoststubgen.x.@0
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
new file mode 100644
index 0000000..207ba52
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen
+
+/**
+ * We will not print the stack trace for exceptions implementing it.
+ */
+interface UserErrorException
+
+/**
+ * Exceptions about parsing class files.
+ */
+class ClassParseException(message: String) : Exception(message)
+
+/**
+ * Use it for internal exception that really shouldn't happen.
+ */
+class HostStubGenInternalException(message: String) : Exception(message)
+
+/**
+ * Exceptions about the content in a jar file.
+ */
+class InvalidJarFileException(message: String) : Exception(message), UserErrorException
+
+/**
+ * Exceptions missing classes, fields, methods, etc.
+ */
+class UnknownApiException(message: String) : Exception(message), UserErrorException
+
+/**
+ * Exceptions related to invalid annotations -- e.g. more than one visibility annotation
+ * on a single API.
+ */
+class InvalidAnnotationException(message: String) : Exception(message), UserErrorException
+
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
new file mode 100644
index 0000000..8db4b69
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -0,0 +1,402 @@
+/*
+ * 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.hoststubgen
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.filters.AnnotationBasedFilter
+import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
+import com.android.hoststubgen.filters.ConstantFilter
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.ImplicitOutputFilter
+import com.android.hoststubgen.filters.KeepAllClassesFilter
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.filters.StubIntersectingFilter
+import com.android.hoststubgen.filters.createFilterFromTextPolicyFile
+import com.android.hoststubgen.filters.printAsTextPolicy
+import com.android.hoststubgen.visitors.BaseAdapter
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.tree.ClassNode
+import org.objectweb.asm.util.CheckClassAdapter
+import java.io.BufferedInputStream
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.io.OutputStream
+import java.io.PrintWriter
+import java.util.zip.ZipEntry
+import java.util.zip.ZipFile
+import java.util.zip.ZipOutputStream
+
+/**
+ * Actual main class.
+ */
+class HostStubGen(val options: HostStubGenOptions) {
+    fun run() {
+        val errors = HostStubGenErrors()
+
+        // Load all classes.
+        val allClasses = loadClassStructures(options.inJar)
+
+        // Dump the classes, if specified.
+        options.inputJarDumpFile?.let {
+            PrintWriter(it).use { pw -> allClasses.dump(pw) }
+            log.i("Dump file created at $it")
+        }
+
+        options.inputJarAsKeepAllFile?.let {
+            PrintWriter(it).use {
+                pw -> allClasses.forEach {
+                    classNode -> printAsTextPolicy(pw, classNode)
+                }
+            }
+            log.i("Dump file created at $it")
+        }
+
+        // Build the filters.
+        val filter = buildFilter(errors, allClasses, options)
+
+        // Transform the jar.
+        convert(
+                options.inJar,
+                options.outStubJar,
+                options.outImplJar,
+                filter,
+                options.enableClassChecker,
+                allClasses,
+                errors,
+        )
+    }
+
+    /**
+     * Load all the classes, without code.
+     */
+    private fun loadClassStructures(inJar: String): ClassNodes {
+        log.i("Reading class structure from $inJar ...")
+        val start = System.currentTimeMillis()
+
+        val allClasses = ClassNodes()
+
+        log.withIndent {
+            ZipFile(inJar).use { inZip ->
+                val inEntries = inZip.entries()
+
+                while (inEntries.hasMoreElements()) {
+                    val entry = inEntries.nextElement()
+
+                    BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+                        if (entry.name.endsWith(".class")) {
+                            val cr = ClassReader(bis)
+                            val cn = ClassNode()
+                            cr.accept(cn, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG
+                                    or ClassReader.SKIP_FRAMES)
+                            if (!allClasses.addClass(cn)) {
+                                log.w("Duplicate class found: ${cn.name}")
+                            }
+                        } else if (entry.name.endsWith(".dex")) {
+                            // Seems like it's an ART jar file. We can't process it.
+                            // It's a fatal error.
+                            throw InvalidJarFileException(
+                                    "$inJar is not a desktop jar file. It contains a *.dex file.")
+                        } else {
+                            // Unknown file type. Skip.
+                            while (bis.available() > 0) {
+                                bis.skip((1024 * 1024).toLong())
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (allClasses.size == 0) {
+            log.w("$inJar contains no *.class files.")
+        }
+
+        val end = System.currentTimeMillis()
+        log.v("Done reading class structure in %.1f second(s).", (end - start) / 1000.0)
+        return allClasses
+    }
+
+    /**
+     * Build the filter, which decides what classes/methods/fields should be put in stub or impl
+     * jars, and "how". (e.g. with substitution?)
+     */
+    private fun buildFilter(
+            errors: HostStubGenErrors,
+            allClasses: ClassNodes,
+            options: HostStubGenOptions,
+            ): OutputFilter {
+        // We build a "chain" of multiple filters here.
+        //
+        // The filters are build in from "inside", meaning the first filter created here is
+        // the last filter used, so it has the least precedence.
+        //
+        // So, for example, the "remove" annotation, which is handled by AnnotationBasedFilter,
+        // can override a class-wide annotation, which is handled by
+        // ClassWidePolicyPropagatingFilter, and any annotations can be overridden by the
+        // text-file based filter, which is handled by parseTextFilterPolicyFile.
+
+        // The first filter is for the default policy from the command line options.
+        var filter: OutputFilter = ConstantFilter(options.defaultPolicy, "default-by-options")
+
+        // Next, we need a filter that resolves "class-wide" policies.
+        // This is used when a member (methods, fields, nested classes) don't get any polices
+        // from upper filters. e.g. when a method has no annotations, then this filter will apply
+        // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
+        val classWidePropagator = ClassWidePolicyPropagatingFilter(filter)
+
+        // Next, Java annotation based filter.
+        filter = AnnotationBasedFilter(
+                errors,
+                allClasses,
+                options.stubAnnotations,
+                options.keepAnnotations,
+                options.stubClassAnnotations,
+                options.keepClassAnnotations,
+                options.throwAnnotations,
+                options.removeAnnotations,
+                options.substituteAnnotations,
+                options.nativeSubstituteAnnotations,
+                options.classLoadHookAnnotations,
+                classWidePropagator
+        )
+
+        // Next, "text based" filter, which allows to override polices without touching
+        // the target code.
+        options.policyOverrideFile?.let {
+            filter = createFilterFromTextPolicyFile(it, allClasses, filter)
+        }
+
+        // If `--intersect-stub-jar` is provided, load from these jar files too.
+        // We use this to restrict stub APIs to public/system/test APIs,
+        // by intersecting with a stub jar file created by metalava.
+        if (options.intersectStubJars.size > 0) {
+            val intersectingJars = loadIntersectingJars(options.intersectStubJars)
+
+            filter = StubIntersectingFilter(errors, intersectingJars, filter)
+        }
+
+        // Apply the implicit filter.
+        filter = ImplicitOutputFilter(errors, allClasses, filter)
+
+        // Optionally keep all classes.
+        if (options.keepAllClasses) {
+            filter = KeepAllClassesFilter(filter)
+        }
+
+        return filter
+    }
+
+    /**
+     * Load jar files specified with "--intersect-stub-jar".
+     */
+    private fun loadIntersectingJars(filenames: Set<String>): Map<String, ClassNodes> {
+        val intersectingJars = mutableMapOf<String, ClassNodes>()
+
+        filenames.forEach { filename ->
+            intersectingJars[filename] = loadClassStructures(filename)
+        }
+        return intersectingJars
+    }
+
+    /**
+     * Convert a JAR file into "stub" and "impl" JAR files.
+     */
+    private fun convert(
+            inJar: String,
+            outStubJar: String,
+            outImplJar: String,
+            filter: OutputFilter,
+            enableChecker: Boolean,
+            classes: ClassNodes,
+            errors: HostStubGenErrors,
+            ) {
+        log.i("Converting %s into [stub: %s, impl: %s] ...", inJar, outStubJar, outImplJar)
+        log.i("Checker is %s", if (enableChecker) "enabled" else "disabled")
+
+        val start = System.currentTimeMillis()
+
+        log.withIndent {
+            // Open the input jar file and process each entry.
+            ZipFile(inJar).use { inZip ->
+                ZipOutputStream(FileOutputStream(outStubJar)).use { stubOutStream ->
+                    ZipOutputStream(FileOutputStream(outImplJar)).use { implOutStream ->
+                        val inEntries = inZip.entries()
+                        while (inEntries.hasMoreElements()) {
+                            val entry = inEntries.nextElement()
+                            convertSingleEntry(inZip, entry, stubOutStream, implOutStream,
+                                    filter, enableChecker, classes, errors)
+                        }
+                        log.i("Converted all entries.")
+                    }
+                }
+                log.i("Created stub: $outStubJar")
+                log.i("Created impl: $outImplJar")
+            }
+        }
+        val end = System.currentTimeMillis()
+        log.v("Done transforming the jar in %.1f second(s).", (end - start) / 1000.0)
+    }
+
+    /**
+     * Convert a single ZIP entry, which may or may not be a class file.
+     */
+    private fun convertSingleEntry(
+            inZip: ZipFile,
+            entry: ZipEntry,
+            stubOutStream: ZipOutputStream,
+            implOutStream: ZipOutputStream,
+            filter: OutputFilter,
+            enableChecker: Boolean,
+            classes: ClassNodes,
+            errors: HostStubGenErrors,
+            ) {
+        log.d("Entry: %s", entry.name)
+        log.withIndent {
+            val name = entry.name
+
+            // Just ignore all the directories. (TODO: make sure it's okay)
+            if (name.endsWith("/")) {
+                return
+            }
+
+            // If it's a class, convert it.
+            if (name.endsWith(".class")) {
+                processSingleClass(inZip, entry, stubOutStream, implOutStream, filter,
+                        enableChecker, classes, errors)
+                return
+            }
+
+            // Handle other file types...
+
+            // - *.uau seems to contain hidden API information.
+            // -  *_compat_config.xml is also about compat-framework.
+            if (name.endsWith(".uau") ||
+                    name.endsWith("_compat_config.xml")) {
+                log.d("Not needed: %s", entry.name)
+                return
+            }
+
+            // Unknown type, we just copy it to both output zip files.
+            // TODO: We probably shouldn't do it for stub jar?
+            log.v("Copying: %s", entry.name)
+            copyZipEntry(inZip, entry, stubOutStream)
+            copyZipEntry(inZip, entry, implOutStream)
+        }
+    }
+
+    /**
+     * Copy a single ZIP entry to the output.
+     */
+    private fun copyZipEntry(
+            inZip: ZipFile,
+            entry: ZipEntry,
+            out: ZipOutputStream,
+            ) {
+        BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+            // Copy unknown entries as is to the impl out. (but not to the stub out.)
+            val outEntry = ZipEntry(entry.name)
+            out.putNextEntry(outEntry)
+            while (bis.available() > 0) {
+                out.write(bis.read())
+            }
+            out.closeEntry()
+        }
+    }
+
+    /**
+     * Convert a single class to "stub" and "impl".
+     */
+    private fun processSingleClass(
+            inZip: ZipFile,
+            entry: ZipEntry,
+            stubOutStream: ZipOutputStream,
+            implOutStream: ZipOutputStream,
+            filter: OutputFilter,
+            enableChecker: Boolean,
+            classes: ClassNodes,
+            errors: HostStubGenErrors,
+            ) {
+        val className = entry.name.replaceFirst("\\.class$".toRegex(), "")
+        val classPolicy = filter.getPolicyForClass(className)
+        if (classPolicy.policy == FilterPolicy.Remove) {
+            log.d("Removing class: %s %s", className, classPolicy)
+            return
+        }
+        // Generate stub first.
+        if (classPolicy.policy.needsInStub) {
+            log.v("Creating stub class: %s Policy: %s", className, classPolicy)
+            log.withIndent {
+                BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+                    val newEntry = ZipEntry(entry.name)
+                    stubOutStream.putNextEntry(newEntry)
+                    convertClass(/*forImpl=*/false, bis, stubOutStream, filter, enableChecker,
+                            classes, errors)
+                    stubOutStream.closeEntry()
+                }
+            }
+        }
+        log.v("Creating impl class: %s Policy: %s", className, classPolicy)
+        if (classPolicy.policy.needsInImpl) {
+            log.withIndent {
+                BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
+                    val newEntry = ZipEntry(entry.name)
+                    implOutStream.putNextEntry(newEntry)
+                    convertClass(/*forImpl=*/true, bis, implOutStream, filter, enableChecker,
+                            classes, errors)
+                    implOutStream.closeEntry()
+                }
+            }
+        }
+    }
+
+    /**
+     * Convert a single class to either "stub" or "impl".
+     */
+    private fun convertClass(
+        forImpl: Boolean,
+        input: InputStream,
+        out: OutputStream,
+        filter: OutputFilter,
+        enableChecker: Boolean,
+        classes: ClassNodes,
+        errors: HostStubGenErrors,
+        ) {
+        val cr = ClassReader(input)
+
+        // COMPUTE_FRAMES wouldn't be happy if code uses
+        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
+        val cw = ClassWriter(flags)
+
+        // Connect to the class writer
+        var outVisitor: ClassVisitor = cw
+        if (enableChecker) {
+            outVisitor = CheckClassAdapter(outVisitor)
+        }
+        val visitorOptions = BaseAdapter.Options(
+                enablePreTrace = options.enablePreTrace,
+                enablePostTrace = options.enablePostTrace,
+                enableMethodLogging = options.enablePreTrace,
+                enableNonStubMethodCallDetection = options.enableNonStubMethodCallDetection,
+                errors = errors,
+        )
+        outVisitor = BaseAdapter.getVisitor(classes, outVisitor, filter, forImpl, visitorOptions)
+
+        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
+        val data = cw.toByteArray()
+        out.write(data)
+    }
+}
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
similarity index 67%
copy from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
copy to tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
index 24064b1..9df0489 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
@@ -13,14 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.hoststubgen
 
-package com.android.systemui.scene.ui.composable
-
-import com.android.systemui.scene.shared.model.Scene
-import dagger.Module
-import dagger.multibindings.Multibinds
-
-@Module
-interface SceneModule {
-    @Multibinds fun scenes(): Set<Scene>
-}
+class HostStubGenErrors {
+    fun onErrorFound(message: String) {
+        // For now, we just throw as soon as any error is found, but eventually we should keep
+        // all errors and print them at the end.
+        throw RuntimeException(message)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
new file mode 100644
index 0000000..5e71a36
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
@@ -0,0 +1,198 @@
+/*
+ * 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.hoststubgen
+
+import java.io.OutputStream
+import java.io.PrintStream
+
+val log: HostStubGenLogger = HostStubGenLogger()
+
+/** Logging level */
+enum class LogLevel {
+    None,
+    Error,
+    Warn,
+    Info,
+    Verbose,
+    Debug,
+}
+
+/** Simple logging class. */
+class HostStubGenLogger(
+        private var out: PrintStream = System.out!!,
+        var level: LogLevel = LogLevel.Info,
+) {
+    companion object {
+        private val sNullPrintStream: PrintStream = PrintStream(OutputStream.nullOutputStream())
+    }
+
+    private var indentLevel: Int = 0
+        get() = field
+        set(value) {
+            field = value
+            indent = "  ".repeat(value)
+        }
+    private var indent: String = ""
+
+    fun indent() {
+        indentLevel++
+    }
+
+    fun unindent() {
+        if (indentLevel <= 0) {
+            throw IllegalStateException("Unbalanced unindent() call.")
+        }
+        indentLevel--
+    }
+
+    inline fun <T> withIndent(block: () -> T): T {
+        try {
+            indent()
+            return block()
+        } finally {
+            unindent()
+        }
+    }
+
+    fun isEnabled(level: LogLevel): Boolean {
+        return level.ordinal <= this.level.ordinal
+    }
+
+    private fun println(message: String) {
+        out.print(indent)
+        out.println(message)
+    }
+
+    /** Log an error. */
+    fun e(message: String) {
+        if (level.ordinal < LogLevel.Error.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log an error. */
+    fun e(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Error.ordinal) {
+            return
+        }
+        e(String.format(format, *args))
+    }
+
+    /** Log a warning. */
+    fun w(message: String) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a warning. */
+    fun w(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        w(String.format(format, *args))
+    }
+
+    /** Log an info message. */
+    fun i(message: String) {
+        if (level.ordinal < LogLevel.Info.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a debug message. */
+    fun i(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        i(String.format(format, *args))
+    }
+
+    /** Log a verbose message. */
+    fun v(message: String) {
+        if (level.ordinal < LogLevel.Verbose.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a verbose message. */
+    fun v(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Verbose.ordinal) {
+            return
+        }
+        v(String.format(format, *args))
+    }
+
+    /** Log a debug message. */
+    fun d(message: String) {
+        if (level.ordinal < LogLevel.Debug.ordinal) {
+            return
+        }
+        println(message)
+    }
+
+    /** Log a debug message. */
+    fun d(format: String, vararg args: Any?) {
+        if (level.ordinal < LogLevel.Warn.ordinal) {
+            return
+        }
+        d(String.format(format, *args))
+    }
+
+    inline fun forVerbose(block: () -> Unit) {
+        if (isEnabled(LogLevel.Verbose)) {
+            block()
+        }
+    }
+
+    inline fun forDebug(block: () -> Unit) {
+        if (isEnabled(LogLevel.Debug)) {
+            block()
+        }
+    }
+
+    /** Return a stream for error. */
+    fun getErrorPrintStream(): PrintStream {
+        if (level.ordinal < LogLevel.Error.ordinal) {
+            return sNullPrintStream
+        }
+
+        // TODO Apply indent
+        return PrintStream(out)
+    }
+
+    /** Return a stream for verbose messages. */
+    fun getVerbosePrintStream(): PrintStream {
+        if (level.ordinal < LogLevel.Verbose.ordinal) {
+            return sNullPrintStream
+        }
+        // TODO Apply indent
+        return PrintStream(out)
+    }
+
+    /** Return a stream for debug messages. */
+    fun getInfoPrintStream(): PrintStream {
+        if (level.ordinal < LogLevel.Info.ordinal) {
+            return sNullPrintStream
+        }
+        // TODO Apply indent
+        return PrintStream(out)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
new file mode 100644
index 0000000..9a54ecf
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -0,0 +1,307 @@
+/*
+ * 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.hoststubgen
+
+import com.android.hoststubgen.filters.FilterPolicy
+import java.io.BufferedReader
+import java.io.File
+import java.io.FileReader
+
+/**
+ * Options that can be set from command line arguments.
+ */
+class HostStubGenOptions(
+        /** Input jar file*/
+        var inJar: String = "",
+
+        /** Output stub jar file */
+        var outStubJar: String = "",
+
+        /** Output implementation jar file */
+        var outImplJar: String = "",
+
+        var inputJarDumpFile: String? = null,
+
+        var inputJarAsKeepAllFile: String? = null,
+
+        var stubAnnotations: MutableSet<String> = mutableSetOf(),
+        var keepAnnotations: MutableSet<String> = mutableSetOf(),
+        var throwAnnotations: MutableSet<String> = mutableSetOf(),
+        var removeAnnotations: MutableSet<String> = mutableSetOf(),
+        var stubClassAnnotations: MutableSet<String> = mutableSetOf(),
+        var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
+
+        var substituteAnnotations: MutableSet<String> = mutableSetOf(),
+        var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(),
+        var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
+
+        var intersectStubJars: MutableSet<String> = mutableSetOf(),
+
+        var policyOverrideFile: String? = null,
+
+        var defaultPolicy: FilterPolicy = FilterPolicy.Remove,
+        var keepAllClasses: Boolean = false,
+
+        var logLevel: LogLevel = LogLevel.Info,
+
+        var cleanUpOnError: Boolean = false,
+
+        var enableClassChecker: Boolean = false,
+        var enablePreTrace: Boolean = false,
+        var enablePostTrace: Boolean = false,
+
+        var enableMethodLogging: Boolean = false,
+
+        var enableNonStubMethodCallDetection: Boolean = true,
+) {
+    companion object {
+
+        private fun String.ensureFileExists(): String {
+            if (!File(this).exists()) {
+                throw InputFileNotFoundException(this)
+            }
+            return this
+        }
+
+        fun parseArgs(args: Array<String>): HostStubGenOptions {
+            val ret = HostStubGenOptions()
+
+            val ai = ArgIterator(expandAtFiles(args))
+
+            var allAnnotations = mutableSetOf<String>()
+
+            fun ensureUniqueAnnotation(name: String): String {
+                if (!allAnnotations.add(name)) {
+                    throw DuplicateAnnotationException(ai.current)
+                }
+                return name
+            }
+
+            while (true) {
+                val arg = ai.nextArgOptional()
+                if (arg == null) {
+                    break
+                }
+
+                when (arg) {
+                    // TODO: Write help
+                    "-h", "--h" -> TODO("Help is not implemented yet")
+
+                    "-v", "--verbose" -> ret.logLevel = LogLevel.Verbose
+                    "-d", "--debug" -> ret.logLevel = LogLevel.Debug
+                    "-q", "--quiet" -> ret.logLevel = LogLevel.None
+
+                    "--in-jar" -> ret.inJar = ai.nextArgRequired(arg).ensureFileExists()
+                    "--out-stub-jar" -> ret.outStubJar = ai.nextArgRequired(arg)
+                    "--out-impl-jar" -> ret.outImplJar = ai.nextArgRequired(arg)
+
+                    "--policy-override-file" ->
+                        ret.policyOverrideFile = ai.nextArgRequired(arg).ensureFileExists()
+
+                    "--clean-up-on-error" -> ret.cleanUpOnError = true
+                    "--no-clean-up-on-error" -> ret.cleanUpOnError = false
+
+                    "--default-remove" -> ret.defaultPolicy = FilterPolicy.Remove
+                    "--default-throw" -> ret.defaultPolicy = FilterPolicy.Throw
+                    "--default-keep" -> ret.defaultPolicy = FilterPolicy.Keep
+                    "--default-stub" -> ret.defaultPolicy = FilterPolicy.Stub
+
+                    "--keep-all-classes" -> ret.keepAllClasses = true
+                    "--no-keep-all-classes" -> ret.keepAllClasses = false
+
+                    "--stub-annotation" ->
+                        ret.stubAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--keep-annotation" ->
+                        ret.keepAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--stub-class-annotation" ->
+                        ret.stubClassAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--keep-class-annotation" ->
+                        ret.keepClassAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--throw-annotation" ->
+                        ret.throwAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--remove-annotation" ->
+                        ret.removeAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--substitute-annotation" ->
+                        ret.substituteAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--native-substitute-annotation" ->
+                        ret.nativeSubstituteAnnotations +=
+                                ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--class-load-hook-annotation" ->
+                        ret.classLoadHookAnnotations +=
+                            ensureUniqueAnnotation(ai.nextArgRequired(arg))
+
+                    "--intersect-stub-jar" ->
+                        ret.intersectStubJars += ai.nextArgRequired(arg).ensureFileExists()
+
+                    "--gen-keep-all-file" ->
+                        ret.inputJarAsKeepAllFile = ai.nextArgRequired(arg)
+
+                    // Following options are for debugging.
+                    "--enable-class-checker" -> ret.enableClassChecker = true
+                    "--no-class-checker" -> ret.enableClassChecker = false
+
+                    "--enable-pre-trace" -> ret.enablePreTrace = true
+                    "--no-pre-trace" -> ret.enablePreTrace = false
+
+                    "--enable-post-trace" -> ret.enablePostTrace = true
+                    "--no-post-trace" -> ret.enablePostTrace = false
+
+                    "--enable-method-logging" -> ret.enableMethodLogging = true
+                    "--no-method-logging" -> ret.enableMethodLogging = false
+
+                    "--enable-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = true
+                    "--no-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = false
+
+                    "--gen-input-dump-file" -> ret.inputJarDumpFile = ai.nextArgRequired(arg)
+
+                    else -> throw ArgumentsException("Unknown option: $arg")
+                }
+            }
+            if (ret.inJar.isEmpty()) {
+                throw ArgumentsException("Required option missing: --in-jar")
+            }
+            if (ret.outStubJar.isEmpty()) {
+                throw ArgumentsException("Required option missing: --out-stub-jar")
+            }
+            if (ret.outImplJar.isEmpty()) {
+                throw ArgumentsException("Required option missing: --out-impl-jar")
+            }
+
+            return ret
+        }
+
+        /**
+         * Scan the arguments, and if any of them starts with an `@`, then load from the file
+         * and use its content as arguments.
+         *
+         * In this file, each line is treated as a single argument.
+         *
+         * The file can contain '#' as comments.
+         */
+        private fun expandAtFiles(args: Array<String>): List<String> {
+            val ret = mutableListOf<String>()
+
+            args.forEach { arg ->
+                if (!arg.startsWith('@')) {
+                    ret += arg
+                    return@forEach
+                }
+                // Read from the file, and add each line to the result.
+                val filename = arg.substring(1).ensureFileExists()
+
+                log.v("Expanding options file $filename")
+
+                BufferedReader(FileReader(filename)).use { reader ->
+                    while (true) {
+                        var line = reader.readLine()
+                        if (line == null) {
+                            break // EOF
+                        }
+
+                        line = normalizeTextLine(line)
+                        if (line.isNotEmpty()) {
+                            ret += line
+                        }
+                    }
+                }
+            }
+            return ret
+        }
+    }
+
+    open class ArgumentsException(message: String?) : Exception(message), UserErrorException
+
+    /** Thrown when the same annotation is used with different annotation arguments. */
+    class DuplicateAnnotationException(annotationName: String?) :
+            ArgumentsException("Duplicate annotation specified: '$annotationName'")
+
+    /** Thrown when an input file does not exist. */
+    class InputFileNotFoundException(filename: String) :
+            ArgumentsException("File '$filename' not found")
+
+    private class ArgIterator(
+            private val args: List<String>,
+            private var currentIndex: Int = -1
+    ) {
+        val current: String
+            get() = args.get(currentIndex)
+
+        /**
+         * Get the next argument, or [null] if there's no more arguments.
+         */
+        fun nextArgOptional(): String? {
+            if ((currentIndex + 1) >= args.size) {
+                return null
+            }
+            return args.get(++currentIndex)
+        }
+
+        /**
+         * Get the next argument, or throw if
+         */
+        fun nextArgRequired(argName: String): String {
+            nextArgOptional().let {
+                if (it == null) {
+                    throw ArgumentsException("Missing parameter for option $argName")
+                }
+                if (it.isEmpty()) {
+                    throw ArgumentsException("Parameter can't be empty for option $argName")
+                }
+                return it
+            }
+        }
+    }
+
+    override fun toString(): String {
+        return """
+            HostStubGenOptions{
+              inJar='$inJar',
+              outStubJar='$outStubJar',
+              outImplJar='$outImplJar',
+              inputJarDumpFile=$inputJarDumpFile,
+              inputJarAsKeepAllFile=$inputJarAsKeepAllFile,
+              stubAnnotations=$stubAnnotations,
+              keepAnnotations=$keepAnnotations,
+              throwAnnotations=$throwAnnotations,
+              removeAnnotations=$removeAnnotations,
+              stubClassAnnotations=$stubClassAnnotations,
+              keepClassAnnotations=$keepClassAnnotations,
+              substituteAnnotations=$substituteAnnotations,
+              nativeSubstituteAnnotations=$nativeSubstituteAnnotations,
+              classLoadHookAnnotations=$classLoadHookAnnotations,
+              intersectStubJars=$intersectStubJars,
+              policyOverrideFile=$policyOverrideFile,
+              defaultPolicy=$defaultPolicy,
+              keepAllClasses=$keepAllClasses,
+              logLevel=$logLevel,
+              cleanUpOnError=$cleanUpOnError,
+              enableClassChecker=$enableClassChecker,
+              enablePreTrace=$enablePreTrace,
+              enablePostTrace=$enablePostTrace,
+              enableMethodLogging=$enableMethodLogging,
+              enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection,
+            }
+            """.trimIndent()
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt
new file mode 100644
index 0000000..0321d9d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Main.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@file:JvmName("Main")
+
+package com.android.hoststubgen
+
+const val COMMAND_NAME = "HostStubGen"
+
+/**
+ * Entry point.
+ */
+fun main(args: Array<String>) {
+    var success = false
+    var clanupOnError = false
+    try {
+        // Parse the command line arguments.
+        val options = HostStubGenOptions.parseArgs(args)
+        clanupOnError = options.cleanUpOnError
+
+        log.level = options.logLevel
+
+        log.v("HostStubGen started")
+        log.v("Options: $options")
+
+        // Run.
+        HostStubGen(options).run()
+
+        success = true
+    } catch (e: Exception) {
+        log.e("$COMMAND_NAME: Error: ${e.message}")
+        if (e !is UserErrorException) {
+            e.printStackTrace(log.getErrorPrintStream())
+        }
+        if (clanupOnError) {
+            TODO("clanupOnError is not implemented yet")
+        }
+    }
+
+    log.v("HostStubGen finished")
+
+    System.exit(if (success) 0 else 1 )
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
new file mode 100644
index 0000000..9fbd6d0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen
+
+/**
+ * A regex that maches whitespate.
+ */
+val whitespaceRegex = """\s+""".toRegex()
+
+/**
+ * Remove the comment ('#' and following) and surrounding whitespace from a line.
+ */
+fun normalizeTextLine(s: String): String {
+    // Remove # and after. (comment)
+    val pos = s.indexOf('#')
+    val uncommented = if (pos < 0) s else s.substring(0, pos)
+
+    // Remove surrounding whitespace.
+    return uncommented.trim()
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
new file mode 100644
index 0000000..a51bdcf
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -0,0 +1,177 @@
+/*
+ * 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.hoststubgen.asm
+
+import com.android.hoststubgen.ClassParseException
+import com.android.hoststubgen.HostStubGenInternalException
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Type
+import org.objectweb.asm.tree.AnnotationNode
+import org.objectweb.asm.tree.ClassNode
+
+
+/** Name of the class initializer method. */
+val CLASS_INITIALIZER_NAME = "<clinit>"
+
+/** Descriptor of the class initializer method. */
+val CLASS_INITIALIZER_DESC = "()V"
+
+/**
+ * Find any of [anyAnnotations] from the list of visible / invisible annotations.
+ */
+fun findAnyAnnotation(
+        anyAnnotations: Set<String>,
+        visibleAnnotations: List<AnnotationNode>?,
+        invisibleAnnotations: List<AnnotationNode>?,
+    ): AnnotationNode? {
+    for (an in visibleAnnotations ?: emptyList()) {
+        if (anyAnnotations.contains(an.desc)) {
+            return an
+        }
+    }
+    for (an in invisibleAnnotations ?: emptyList()) {
+        if (anyAnnotations.contains(an.desc)) {
+            return an
+        }
+    }
+    return null
+}
+
+fun findAnnotationValueAsString(an: AnnotationNode, propertyName: String): String? {
+    for (i in 0..(an.values?.size ?: 0) - 2 step 2) {
+        val name = an.values[i]
+
+        if (name != propertyName) {
+            continue
+        }
+        val value = an.values[i + 1]
+        if (value is String) {
+            return value
+        }
+        throw ClassParseException(
+                "The type of '$name' in annotation \"${an.desc}\" must be String" +
+                        ", but is ${value?.javaClass?.canonicalName}")
+    }
+    return null
+}
+
+private val removeLastElement = """[./][^./]*$""".toRegex()
+
+fun getPackageNameFromClassName(className: String): String {
+    return className.replace(removeLastElement, "")
+}
+
+fun resolveClassName(className: String, packageName: String): String {
+    if (className.contains('.') || className.contains('/')) {
+        return className
+    }
+    return "$packageName.$className"
+}
+
+fun String.toJvmClassName(): String {
+    return this.replace('.', '/')
+}
+
+fun String.toHumanReadableClassName(): String {
+    return this.replace('/', '.')
+}
+
+fun String.toHumanReadableMethodName(): String {
+    return this.replace('/', '.')
+}
+
+private val numericalInnerClassName = """.*\$\d+$""".toRegex()
+
+fun isAnonymousInnerClass(cn: ClassNode): Boolean {
+    // TODO: Is there a better way?
+    return cn.name.matches(numericalInnerClassName)
+}
+
+/**
+ * Take a class name. If it's a nested class, then return the name of its direct outer class name.
+ * Otherwise, return null.
+ */
+fun getDirectOuterClassName(className: String): String? {
+    val pos = className.indexOf('$')
+    if (pos < 0) {
+        return null
+    }
+    return className.substring(0, pos)
+}
+
+/**
+ * Write bytecode to push all the method arguments to the stack.
+ * The number of arguments and their type are taken from [methodDescriptor].
+ */
+fun writeByteCodeToPushArguments(methodDescriptor: String, writer: MethodVisitor) {
+    var i = -1
+    Type.getArgumentTypes(methodDescriptor).forEach { type ->
+        i++
+
+        // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
+
+        // Note, long and double will consume two local variable spaces, so the extra `i++`.
+        when (type) {
+            Type.VOID_TYPE -> throw HostStubGenInternalException("VOID_TYPE not expected")
+            Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE
+                -> writer.visitVarInsn(Opcodes.ILOAD, i)
+            Type.LONG_TYPE -> writer.visitVarInsn(Opcodes.LLOAD, i++)
+            Type.FLOAT_TYPE -> writer.visitVarInsn(Opcodes.FLOAD, i)
+            Type.DOUBLE_TYPE -> writer.visitVarInsn(Opcodes.DLOAD, i++)
+            else -> writer.visitVarInsn(Opcodes.ALOAD, i)
+        }
+    }
+}
+
+/**
+ * Write bytecode to "RETURN" that matches the method's return type, according to
+ * [methodDescriptor].
+ */
+fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) {
+    Type.getReturnType(methodDescriptor).let { type ->
+        // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
+        when (type) {
+            Type.VOID_TYPE -> writer.visitInsn(Opcodes.RETURN)
+            Type.BOOLEAN_TYPE, Type.INT_TYPE, Type.SHORT_TYPE, Type.CHAR_TYPE
+                -> writer.visitInsn(Opcodes.IRETURN)
+            Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN)
+            Type.FLOAT_TYPE -> writer.visitInsn(Opcodes.FRETURN)
+            Type.DOUBLE_TYPE -> writer.visitInsn(Opcodes.DRETURN)
+            else -> writer.visitInsn(Opcodes.ARETURN)
+        }
+    }
+}
+
+/**
+ * Return the "visibility" modifier from an `access` integer.
+ *
+ * (see https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1)
+ */
+fun getVisibilityModifier(access: Int): Int {
+    return access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED)
+}
+
+/**
+ * Return true if an `access` integer is "private" or "package private".
+ */
+fun isVisibilityPrivateOrPackagePrivate(access: Int): Boolean {
+    return when (getVisibilityModifier(access)) {
+        0 -> true // Package private.
+        Opcodes.ACC_PRIVATE -> true
+        else -> false
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
new file mode 100644
index 0000000..4df0bfc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
@@ -0,0 +1,149 @@
+package com.android.hoststubgen.asm
+
+import com.android.hoststubgen.ClassParseException
+import org.objectweb.asm.tree.AnnotationNode
+import org.objectweb.asm.tree.ClassNode
+import org.objectweb.asm.tree.FieldNode
+import org.objectweb.asm.tree.MethodNode
+import org.objectweb.asm.tree.TypeAnnotationNode
+import java.io.PrintWriter
+import java.util.Arrays
+
+/**
+ * Stores all classes loaded from a jar file, in a form of [ClassNode]
+ */
+class ClassNodes {
+    val mAllClasses: MutableMap<String, ClassNode> = HashMap()
+
+    /**
+     * Total number of classes registered.
+     */
+    val size: Int
+        get() = mAllClasses.size
+
+    /** Add a [ClassNode] */
+    fun addClass(cn: ClassNode): Boolean {
+        if (mAllClasses.containsKey(cn.name)) {
+            return false
+        }
+        mAllClasses[cn.name.toJvmClassName()] = cn
+        return true
+    }
+
+    /** Get a class's [ClassNodes] (which may not exist) */
+    fun findClass(name: String): ClassNode? {
+        return mAllClasses[name.toJvmClassName()]
+    }
+
+    /** Get a class's [ClassNodes] (which must exists) */
+    fun getClass(name: String): ClassNode {
+        return findClass(name) ?: throw ClassParseException("Class $name not found")
+    }
+
+    /** Find a field, which may not exist. */
+    fun findField(
+            className: String,
+            fieldName: String,
+    ): FieldNode? {
+        return findClass(className)?.fields?.firstOrNull { it.name == fieldName }?.let { fn ->
+            return fn
+        }
+    }
+
+    /** Find a method, which may not exist. */
+    fun findMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+    ): MethodNode? {
+        return findClass(className)?.methods
+                ?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+            return mn
+        }
+    }
+
+    /** @return true if a class has a class initializer. */
+    fun hasClassInitializer(className: String): Boolean {
+        return findMethod(className, CLASS_INITIALIZER_NAME, CLASS_INITIALIZER_DESC) != null
+    }
+
+    /** Run the lambda on each class in alphabetical order. */
+    fun forEach(consumer: (classNode: ClassNode) -> Unit) {
+        val keys = mAllClasses.keys.toTypedArray()
+        Arrays.sort(keys)
+
+        for (name in keys) {
+            consumer(mAllClasses[name]!!)
+        }
+    }
+
+    /**
+     * Dump all classes.
+     */
+    fun dump(pw: PrintWriter) {
+        forEach { classNode -> dumpClass(pw, classNode) }
+    }
+
+    private fun dumpClass(pw: PrintWriter, cn: ClassNode) {
+        pw.printf("Class: %s [access: %x]\n", cn.name, cn.access)
+        dumpAnnotations(pw, "  ",
+                cn.visibleTypeAnnotations, cn.invisibleTypeAnnotations,
+                cn.visibleAnnotations, cn.invisibleAnnotations,
+                )
+
+        for (f in cn.fields ?: emptyList()) {
+            pw.printf("  Field: %s [sig: %s] [desc: %s] [access: %x]\n",
+                    f.name, f.signature, f.desc, f.access)
+            dumpAnnotations(pw, "    ",
+                    f.visibleTypeAnnotations, f.invisibleTypeAnnotations,
+                    f.visibleAnnotations, f.invisibleAnnotations,
+                    )
+        }
+        for (m in cn.methods ?: emptyList()) {
+            pw.printf("  Method: %s [sig: %s] [desc: %s] [access: %x]\n",
+                    m.name, m.signature, m.desc, m.access)
+            dumpAnnotations(pw, "    ",
+                    m.visibleTypeAnnotations, m.invisibleTypeAnnotations,
+                    m.visibleAnnotations, m.invisibleAnnotations,
+                    )
+        }
+    }
+
+    private fun dumpAnnotations(
+        pw: PrintWriter,
+        prefix: String,
+        visibleTypeAnnotations: List<TypeAnnotationNode>?,
+        invisibleTypeAnnotations: List<TypeAnnotationNode>?,
+        visibleAnnotations: List<AnnotationNode>?,
+        invisibleAnnotations: List<AnnotationNode>?,
+        ) {
+        for (an in visibleTypeAnnotations ?: emptyList()) {
+            pw.printf("%sTypeAnnotation(vis): %s\n", prefix, an.desc)
+        }
+        for (an in invisibleTypeAnnotations ?: emptyList()) {
+            pw.printf("%sTypeAnnotation(inv): %s\n", prefix, an.desc)
+        }
+        for (an in visibleAnnotations ?: emptyList()) {
+            pw.printf("%sAnnotation(vis): %s\n", prefix, an.desc)
+            if (an.values == null) {
+                continue
+            }
+            var i = 0
+            while (i < an.values.size - 1) {
+                pw.printf("%s  - %s -> %s \n", prefix, an.values[i], an.values[i + 1])
+                i += 2
+            }
+        }
+        for (an in invisibleAnnotations ?: emptyList()) {
+            pw.printf("%sAnnotation(inv): %s\n", prefix, an.desc)
+            if (an.values == null) {
+                continue
+            }
+            var i = 0
+            while (i < an.values.size - 1) {
+                pw.printf("%s  - %s -> %s \n", prefix, an.values[i], an.values[i + 1])
+                i += 2
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
new file mode 100644
index 0000000..454569d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -0,0 +1,401 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.ClassParseException
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.HostStubGenInternalException
+import com.android.hoststubgen.InvalidAnnotationException
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.findAnnotationValueAsString
+import com.android.hoststubgen.asm.findAnyAnnotation
+import com.android.hoststubgen.asm.toHumanReadableMethodName
+import com.android.hoststubgen.asm.toJvmClassName
+import com.android.hoststubgen.log
+import org.objectweb.asm.tree.AnnotationNode
+import org.objectweb.asm.tree.ClassNode
+
+// TODO: Detect invalid cases, such as...
+// - Class's visibility is lower than the members'.
+// - HostSideTestSubstituteWith is set, but it doesn't have @Stub or @Keep
+
+/**
+ * [OutputFilter] using Java annotations.
+ */
+class AnnotationBasedFilter(
+        private val errors: HostStubGenErrors,
+        private val classes: ClassNodes,
+        stubAnnotations_: Set<String>,
+        keepAnnotations_: Set<String>,
+        stubClassAnnotations_: Set<String>,
+        keepClassAnnotations_: Set<String>,
+        throwAnnotations_: Set<String>,
+        removeAnnotations_: Set<String>,
+        substituteAnnotations_: Set<String>,
+        nativeSubstituteAnnotations_: Set<String>,
+        classLoadHookAnnotations_: Set<String>,
+        fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+    private var stubAnnotations = convertToInternalNames(stubAnnotations_)
+    private var keepAnnotations = convertToInternalNames(keepAnnotations_)
+    private var stubClassAnnotations = convertToInternalNames(stubClassAnnotations_)
+    private var keepClassAnnotations = convertToInternalNames(keepClassAnnotations_)
+    private var throwAnnotations = convertToInternalNames(throwAnnotations_)
+    private var removeAnnotations = convertToInternalNames(removeAnnotations_)
+    private var substituteAnnotations = convertToInternalNames(substituteAnnotations_)
+    private var nativeSubstituteAnnotations = convertToInternalNames(nativeSubstituteAnnotations_)
+    private var classLoadHookAnnotations = convertToInternalNames(classLoadHookAnnotations_)
+
+    /** Annotations that control API visibility. */
+    private var visibilityAnnotations: Set<String> = convertToInternalNames(
+        stubAnnotations_ +
+        keepAnnotations_ +
+        stubClassAnnotations_ +
+        keepClassAnnotations_ +
+        throwAnnotations_ +
+        removeAnnotations_)
+
+    /**
+     * All the annotations we use. Note, this one is in a [convertToJvmNames] format unlike
+     * other ones, because of how it's used.
+     */
+    private var allAnnotations: Set<String> = convertToJvmNames(
+        stubAnnotations_ +
+                keepAnnotations_ +
+                stubClassAnnotations_ +
+                keepClassAnnotations_ +
+                throwAnnotations_ +
+                removeAnnotations_ +
+                substituteAnnotations_ +
+                nativeSubstituteAnnotations_ +
+                classLoadHookAnnotations_)
+
+    private val substitutionHelper = SubstitutionHelper()
+
+    private val reasonAnnotation = "annotation"
+    private val reasonClassAnnotation = "class-annotation"
+
+    /**
+     * Throw if an item has more than one visibility annotations.
+     *
+     * name1 - 4 are only used in exception messages. We take them as separate strings
+     * to avoid unnecessary string concatenations.
+     */
+    private fun detectInvalidAnnotations(
+        visibles: List<AnnotationNode>?,
+        invisibles: List<AnnotationNode>?,
+        type: String,
+        name1: String,
+        name2: String,
+        name3: String,
+    ) {
+        var count = 0
+        for (an in visibles ?: emptyList()) {
+            if (visibilityAnnotations.contains(an.desc)) {
+                count++
+            }
+        }
+        for (an in invisibles ?: emptyList()) {
+            if (visibilityAnnotations.contains(an.desc)) {
+                count++
+            }
+        }
+        if (count > 1) {
+            val description = if (name2 == "" && name3 == "") {
+                "$type $name1"
+            } else {
+                "$type $name1.$name2$name3"
+            }
+            throw InvalidAnnotationException(
+                "Found more than one visibility annotations on $description")
+        }
+    }
+
+    /**
+     * Find a visibility annotation.
+     *
+     * name1 - 4 are only used in exception messages.
+     */
+    private fun findAnnotation(
+        visibles: List<AnnotationNode>?,
+        invisibles: List<AnnotationNode>?,
+        type: String,
+        name1: String,
+        name2: String = "",
+        name3: String = "",
+    ): FilterPolicyWithReason? {
+        detectInvalidAnnotations(visibles, invisibles, type, name1, name2, name3)
+
+        findAnyAnnotation(stubAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Stub.withReason(reasonAnnotation)
+        }
+        findAnyAnnotation(stubClassAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.StubClass.withReason(reasonClassAnnotation)
+        }
+        findAnyAnnotation(keepAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Keep.withReason(reasonAnnotation)
+        }
+        findAnyAnnotation(keepClassAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.KeepClass.withReason(reasonClassAnnotation)
+        }
+        findAnyAnnotation(throwAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Throw.withReason(reasonAnnotation)
+        }
+        findAnyAnnotation(removeAnnotations, visibles, invisibles)?.let {
+            return FilterPolicy.Remove.withReason(reasonAnnotation)
+        }
+        return null
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        val cn = classes.getClass(className)
+
+        findAnnotation(
+            cn.visibleAnnotations,
+            cn.invisibleAnnotations,
+            "class",
+            className)?.let {
+            return it
+        }
+
+        // If it's any of the annotations, then always keep it.
+        if (allAnnotations.contains(className)) {
+            return FilterPolicy.KeepClass.withReason("HostStubGen Annotation")
+        }
+
+        return super.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        val cn = classes.getClass(className)
+
+        cn.fields?.firstOrNull { it.name == fieldName }?.let {fn ->
+            findAnnotation(
+                fn.visibleAnnotations,
+                fn.invisibleAnnotations,
+                "field",
+                className,
+                fieldName
+                )?.let { policy ->
+                // If the item has an annotation, then use it.
+                return policy
+            }
+        }
+        return super.getPolicyForField(className, fieldName)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        val cn = classes.getClass(className)
+
+        cn.methods?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+            // @SubstituteWith is going to complicate the policy here, so we ask helper
+            // what to do.
+            substitutionHelper.getPolicyFromSubstitution(cn, mn.name, mn.desc)?.let {
+                return it
+            }
+
+            // If there's no substitution, then we check the annotation.
+            findAnnotation(
+                mn.visibleAnnotations,
+                mn.invisibleAnnotations,
+                "method",
+                className,
+                methodName,
+                descriptor
+            )?.let { policy ->
+                return policy
+            }
+        }
+        return super.getPolicyForMethod(className, methodName, descriptor)
+    }
+
+    override fun getRenameTo(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): String? {
+        val cn = classes.getClass(className)
+
+        // If the method has a "substitute with" annotation, then return its "value" parameter.
+        cn.methods?.firstOrNull { it.name == methodName && it.desc == descriptor }?.let { mn ->
+            return substitutionHelper.getRenameTo(cn, mn.name, mn.desc)
+        }
+        return null
+    }
+
+    override fun getNativeSubstitutionClass(className: String): String? {
+        classes.getClass(className).let { cn ->
+            findAnyAnnotation(nativeSubstituteAnnotations,
+                    cn.visibleAnnotations, cn.invisibleAnnotations)?.let { an ->
+                return getAnnotationField(an, "value")?.toJvmClassName()
+            }
+        }
+        return null
+    }
+
+    override fun getClassLoadHook(className: String): String? {
+        classes.getClass(className).let { cn ->
+            findAnyAnnotation(classLoadHookAnnotations,
+                cn.visibleAnnotations, cn.invisibleAnnotations)?.let { an ->
+                return getAnnotationField(an, "value")?.toHumanReadableMethodName()
+            }
+        }
+        return null
+    }
+
+    private data class MethodKey(val name: String, val desc: String)
+
+    /**
+     * In order to handle substitution, we need to build a reverse mapping of substitution
+     * methods.
+     *
+     * This class automatically builds such a map internally that the above methods can
+     * take advantage of.
+     */
+    private inner class SubstitutionHelper {
+        private var currentClass: ClassNode? = null
+
+        private var policiesFromSubstitution = mutableMapOf<MethodKey, FilterPolicyWithReason>()
+        private var substituteToMethods = mutableMapOf<MethodKey, String>()
+
+        fun getPolicyFromSubstitution(cn: ClassNode, methodName: String, descriptor: String):
+                FilterPolicyWithReason? {
+            setClass(cn)
+            return policiesFromSubstitution[MethodKey(methodName, descriptor)]
+        }
+
+        fun getRenameTo(cn: ClassNode, methodName: String, descriptor: String): String? {
+            setClass(cn)
+            return substituteToMethods[MethodKey(methodName, descriptor)]
+        }
+
+        /**
+         * Every time we see a different class, we scan all its methods for substitution attributes,
+         * and compute (implicit) policies caused by them.
+         *
+         * For example, for the following methods:
+         *
+         *   @Stub
+         *   @Substitute(suffix = "_host")
+         *   private void foo() {
+         *      // This isn't supported on the host side.
+         *   }
+         *   private void foo_host() {
+         *      // Host side implementation
+         *   }
+         *
+         * We internally handle them as:
+         *
+         *   foo() -> Remove
+         *   foo_host() -> Stub, and then rename it to foo().
+         */
+        private fun setClass(cn: ClassNode) {
+            if (currentClass == cn) {
+                return
+            }
+            // If the class is changing, we'll rebuild the internal structure.
+            currentClass = cn
+
+            policiesFromSubstitution.clear()
+            substituteToMethods.clear()
+
+            for (mn in cn.methods ?: emptyList()) {
+                findAnyAnnotation(substituteAnnotations,
+                        mn.visibleAnnotations,
+                        mn.invisibleAnnotations)?.let { an ->
+
+                    // Find the policy for this method.
+                    val policy = outermostFilter.getPolicyForMethod(cn.name, mn.name, mn.desc)
+                            .policy.resolveClassWidePolicy()
+                    // Make sure it's either Stub or Keep.
+                    if (!(policy.needsInStub || policy.needsInImpl)) {
+                        // TODO: Use the real annotation names in the message
+                        errors.onErrorFound("@SubstituteWith must have either @Stub or @Keep")
+                        return@let
+                    }
+                    if (!policy.isUsableWithMethods) {
+                        throw HostStubGenInternalException("Policy $policy shouldn't show up here")
+                    }
+
+                    val suffix = getAnnotationField(an, "suffix") ?: return@let
+                    val renameFrom = mn.name + suffix
+                    val renameTo = mn.name
+
+                    if (renameFrom == renameTo) {
+                        errors.onErrorFound("@SubstituteWith have a different name")
+                        return@let
+                    }
+
+                    // This mn has "SubstituteWith". This means,
+                        // 1. Re move the "rename-to" method, so add it to substitutedMethods.
+                    policiesFromSubstitution[MethodKey(renameTo, mn.desc)] =
+                            FilterPolicy.Remove.withReason("substitute-to")
+
+                    // 2. We also keep the from-to in the map.
+                    policiesFromSubstitution[MethodKey(renameFrom, mn.desc)] =
+                            policy.withReason("substitute-from")
+                    substituteToMethods[MethodKey(renameFrom, mn.desc)] = renameTo
+
+                    log.v("Substitution found: %s%s -> %s", renameFrom, mn.desc, renameTo)
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the (String) value of 'value' parameter from an annotation.
+     */
+    private fun getAnnotationField(an: AnnotationNode, name: String): String? {
+        try {
+            val suffix = findAnnotationValueAsString(an, name)
+            if (suffix == null) {
+                errors.onErrorFound("Annotation \"${an.desc}\" must have field $name")
+            }
+            return suffix
+        } catch (e: ClassParseException) {
+            errors.onErrorFound(e.message!!)
+            return null
+        }
+    }
+
+    companion object {
+        /**
+         * Convert from human-readable type names (e.g. "com.android.TypeName") to the internal type
+         * names (e.g. "Lcom/android/TypeName).
+         */
+        private fun convertToInternalNames(input: Set<String>): Set<String> {
+            val ret = mutableSetOf<String>()
+            input.forEach { ret.add("L" + it.toJvmClassName() + ";") }
+            return ret
+        }
+
+        /**
+         * Convert from human-readable type names to JVM type names.
+         */
+        private fun convertToJvmNames(input: Set<String>): Set<String> {
+            val ret = mutableSetOf<String>()
+            input.forEach { ret.add(it.toJvmClassName()) }
+            return ret
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
new file mode 100644
index 0000000..6aac3d8
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.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.hoststubgen.filters
+
+import com.android.hoststubgen.asm.getDirectOuterClassName
+
+/**
+ * This is used as the second last fallback filter. This filter propagates the class-wide policy
+ * (obtained from [outermostFilter]) to the fields and methods.
+ */
+class ClassWidePolicyPropagatingFilter(
+        fallback: OutputFilter,
+    ) : DelegatingFilter(fallback) {
+
+    private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? {
+        var currentClass = className
+
+        while (true) {
+            outermostFilter.getPolicyForClass(className).let { policy ->
+                if (policy.policy.isClassWidePolicy) {
+                    val p = if (resolve) policy.policy.resolveClassWidePolicy() else policy.policy
+
+                    return p.withReason(policy.reason).wrapReason("class-wide in $currentClass")
+                }
+                // If the class's policy is remove, then remove it.
+                if (policy.policy == FilterPolicy.Remove) {
+                    return FilterPolicy.Remove.withReason("class-wide in $currentClass")
+                }
+            }
+
+            // Next, look at the outer class...
+            val outer = getDirectOuterClassName(currentClass)
+            if (outer == null) {
+                return null
+            }
+            currentClass = outer
+        }
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        // If it's a nested class, use the outer class's policy.
+        getDirectOuterClassName(className)?.let { outerName ->
+            getClassWidePolicy(outerName, resolve = false)?.let { policy ->
+                return policy
+            }
+        }
+
+        return super.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        return getClassWidePolicy(className, resolve = true)
+                ?: super.getPolicyForField(className, fieldName)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        return getClassWidePolicy(className, resolve = true)
+                ?: super.getPolicyForMethod(className, methodName, descriptor)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
new file mode 100644
index 0000000..33010ba
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.filters
+
+import com.android.hoststubgen.HostStubGenInternalException
+
+
+/**
+ * [OutputFilter] with a given policy. Used to represent the default policy.
+ *
+ * This is used as the last fallback filter.
+ *
+ * @param policy the policy. Cannot be a "substitute" policy.
+ */
+class ConstantFilter(
+        policy: FilterPolicy,
+        val reason: String
+) : OutputFilter() {
+    val classPolicy: FilterPolicy
+    val fieldPolicy: FilterPolicy
+    val methodPolicy: FilterPolicy
+
+    init {
+        if (policy.isSubstitute) {
+            throw HostStubGenInternalException(
+                    "ConstantFilter doesn't allow substitution policies.")
+        }
+        if (policy.isClassWidePolicy) {
+            // We prevent it, because there's no point in using class-wide policies because
+            // all members get othe same policy too anyway.
+            throw HostStubGenInternalException(
+                    "ConstantFilter doesn't allow class-wide policies.")
+        }
+        methodPolicy = policy
+
+        // TODO: Need to think about the realistic default behavior.
+        classPolicy = if (policy != FilterPolicy.Throw) policy else FilterPolicy.Remove
+        fieldPolicy = classPolicy
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return classPolicy.withReason(reason)
+    }
+
+    override fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason {
+        return fieldPolicy.withReason(reason)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            ): FilterPolicyWithReason {
+        return methodPolicy.withReason(reason)
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
new file mode 100644
index 0000000..f0763c4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.hoststubgen.filters
+
+/**
+ * Base class for an [OutputFilter] that uses another filter as a fallback.
+ */
+abstract class DelegatingFilter(
+        // fallback shouldn't be used by subclasses, so make it private.
+        // They should instead be calling into `super` or `outermostFilter`.
+        private val fallback: OutputFilter
+) : OutputFilter() {
+    init {
+        fallback.outermostFilter = this
+    }
+
+    override var outermostFilter: OutputFilter = this
+        get() = field
+        set(value) {
+            field = value
+            // Propagate the inner filters.
+            fallback.outermostFilter = value
+        }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return fallback.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        return fallback.getPolicyForField(className, fieldName)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        return fallback.getPolicyForMethod(className, methodName, descriptor)
+    }
+
+    override fun getRenameTo(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): String? {
+        return fallback.getRenameTo(className, methodName, descriptor)
+    }
+
+    override fun getNativeSubstitutionClass(className: String): String? {
+        return fallback.getNativeSubstitutionClass(className)
+    }
+
+    override fun getClassLoadHook(className: String): String? {
+        return fallback.getClassLoadHook(className)
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
new file mode 100644
index 0000000..f11ac2f
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
@@ -0,0 +1,133 @@
+/*
+ * 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.hoststubgen.filters
+
+enum class FilterPolicy {
+    /**
+     * Keep the item in the stub jar file, so tests can use it.
+     */
+    Stub,
+
+    /**
+     * Keep the item in the impl jar file, but not in the stub file. Tests cannot use it directly,
+     * but indirectly.
+     */
+    Keep,
+
+    /**
+     * Only used for types. Keep the class in the stub, and also all its members.
+     * But each member can have another annotations to override it.
+     */
+    StubClass,
+
+    /**
+     * Only used for types. Keep the class in the impl, not in the stub, and also all its members.
+     * But each member can have another annotations to override it.
+     */
+    KeepClass,
+
+    /**
+     * Same as [Stub], but replace it with a "substitution" method. Only usable with methods.
+     */
+    SubstituteAndStub,
+
+    /**
+     * Same as [Keep], but replace it with a "substitution" method. Only usable with methods.
+     */
+    SubstituteAndKeep,
+
+    /**
+     * Only usable with methods. The item will be kept in the impl jar file, but when called,
+     * it'll throw.
+     */
+    Throw,
+
+    /**
+     * Remove the item completely.
+     */
+    Remove;
+
+    val isSubstitute: Boolean
+        get() = this == SubstituteAndStub || this == SubstituteAndKeep
+
+    val needsInStub: Boolean
+        get() = this == Stub || this == StubClass || this == SubstituteAndStub
+
+    val needsInImpl: Boolean
+        get() = this != Remove
+
+    /** Returns whether a policy can be used with classes */
+    val isUsableWithClasses: Boolean
+        get() {
+            return when (this) {
+                Stub, StubClass, Keep, KeepClass, Remove -> true
+                else -> false
+            }
+        }
+
+    /** Returns whether a policy can be used with fields. */
+    val isUsableWithFields: Boolean
+        get() {
+            return when (this) {
+                Stub, Keep, Remove -> true
+                else -> false
+            }
+        }
+
+    /** Returns whether a policy can be used with methods */
+    val isUsableWithMethods: Boolean
+        get() {
+            return when (this) {
+                StubClass, KeepClass -> false
+                else -> true
+            }
+        }
+
+    /** Returns whether a policy is a class-wide one. */
+    val isClassWidePolicy: Boolean
+        get() {
+            return when (this) {
+                StubClass, KeepClass -> true
+                else -> false
+            }
+        }
+
+    fun getSubstitutionBasePolicy(): FilterPolicy {
+        return when (this) {
+            SubstituteAndKeep -> Keep
+            SubstituteAndStub -> Stub
+            else -> this
+        }
+    }
+
+    /**
+     * Convert {Stub,Keep}Class to the corresponding Stub or Keep.
+     */
+    fun resolveClassWidePolicy(): FilterPolicy {
+        return when (this) {
+            StubClass -> Stub
+            KeepClass -> Keep
+            else -> this
+        }
+    }
+
+    /**
+     * Create a [FilterPolicyWithReason] with a given reason.
+     */
+    fun withReason(reason: String): FilterPolicyWithReason {
+        return FilterPolicyWithReason(this, reason)
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
new file mode 100644
index 0000000..b64a2f5
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.filters
+
+/**
+ * Captures a [FilterPolicy] with a human-readable reason.
+ */
+data class FilterPolicyWithReason (
+        val policy: FilterPolicy,
+        val reason: String = "",
+) {
+    /**
+     * Return a new [FilterPolicy] with an updated reason, while keeping the original reason
+     * as an "inner-reason".
+     */
+    fun wrapReason(reason: String): FilterPolicyWithReason {
+        return FilterPolicyWithReason(policy, "$reason [inner-reason: ${this.reason}]")
+    }
+
+    /**
+     * If the visibility is lower than "Keep" (meaning if it's "remove"),
+     * then return a new [FilterPolicy] with "Keep".
+     * Otherwise, return itself
+     */
+    fun promoteToKeep(promotionReason: String): FilterPolicyWithReason {
+        if (policy.needsInImpl) {
+            return this
+        }
+        val newPolicy = if (policy.isClassWidePolicy) FilterPolicy.KeepClass else FilterPolicy.Keep
+
+        return FilterPolicyWithReason(newPolicy,
+                "$promotionReason [original remove reason: ${this.reason}]")
+    }
+
+    /**
+     * If the visibility is above "Keep" (meaning if it's "stub"),
+     * then return a new [FilterPolicy] with "Keep".
+     * Otherwise, return itself
+     */
+    fun demoteToKeep(promotionReason: String): FilterPolicyWithReason {
+        if (!policy.needsInStub) {
+            return this
+        }
+        val newPolicy = if (policy.isClassWidePolicy) FilterPolicy.KeepClass else FilterPolicy.Keep
+
+        return FilterPolicyWithReason(newPolicy,
+                "$promotionReason [original stub reason: ${this.reason}]")
+    }
+
+    override fun toString(): String {
+        return "[$policy - reason: $reason]"
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
new file mode 100644
index 0000000..9c372ff
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.HostStubGenInternalException
+import com.android.hoststubgen.asm.isAnonymousInnerClass
+import com.android.hoststubgen.log
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
+
+/**
+ * Filter implementing "implicit" rules, such as:
+ * - "keep all anonymous inner classes if the outer class is keep".
+ *   (But anonymous inner classes should never be in "stub")
+ * - For classes in stub, make sure private parameterless constructors are also in stub, if any.
+ */
+class ImplicitOutputFilter(
+        private val errors: HostStubGenErrors,
+        private val classes: ClassNodes,
+        fallback: OutputFilter
+) : DelegatingFilter(fallback) {
+    private fun getClassImplicitPolicy(className: String): FilterPolicyWithReason? {
+        // TODO: This check should be cached.
+        val cn = classes.getClass(className)
+
+        if (isAnonymousInnerClass(cn)) {
+            log.forDebug {
+//                log.d("  anon-inner class: ${className} outer: ${cn.outerClass}  ")
+            }
+            if (cn.outerClass == null) {
+                throw HostStubGenInternalException(
+                        "outerClass is null for anonymous inner class")
+            }
+            // If the outer class needs to be in impl, it should be in impl too.
+            val outerPolicy = outermostFilter.getPolicyForClass(cn.outerClass)
+            if (outerPolicy.policy.needsInImpl) {
+                return FilterPolicy.KeepClass.withReason("anonymous-inner-class")
+            }
+        }
+        return null
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        // Use the implicit policy, if any.
+        getClassImplicitPolicy(className)?.let { return it }
+
+        return super.getPolicyForClass(className)
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        val fallback = super.getPolicyForMethod(className, methodName, descriptor)
+
+        // If the class is in the stub, then we need to put the private constructor in the stub too,
+        // to prevent the class from getting instantiated.
+        if (outermostFilter.getPolicyForClass(className).policy.needsInStub &&
+                !fallback.policy.needsInStub &&
+                (methodName == "<init>") && // Constructor?
+                (descriptor == "()V")) { // Has zero parameters?
+            classes.findMethod(className, methodName, descriptor)?.let { mn ->
+                if (isVisibilityPrivateOrPackagePrivate(mn.access)) {
+                    return FilterPolicy.Stub.withReason("private constructor in stub class")
+                }
+            }
+        }
+
+        return fallback
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
new file mode 100644
index 0000000..f3551d4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.UnknownApiException
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.toHumanReadableClassName
+import com.android.hoststubgen.asm.toHumanReadableMethodName
+
+// TODO: Validate all input names.
+
+class InMemoryOutputFilter(
+    private val classes: ClassNodes,
+    fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+    private val mPolicies: MutableMap<String, FilterPolicyWithReason> = mutableMapOf()
+    private val mRenames: MutableMap<String, String> = mutableMapOf()
+    private val mNativeSubstitutionClasses: MutableMap<String, String> = mutableMapOf()
+    private val mClassLoadHooks: MutableMap<String, String> = mutableMapOf()
+
+    private fun getClassKey(className: String): String {
+        return className.toHumanReadableClassName()
+    }
+
+    private fun getFieldKey(className: String, fieldName: String): String {
+        return getClassKey(className) + "." + fieldName
+    }
+
+    private fun getMethodKey(className: String, methodName: String, signature: String): String {
+        return getClassKey(className) + "." + methodName + ";" + signature
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className)
+    }
+
+    private fun ensureClassExists(className: String) {
+        if (classes.findClass(className) == null) {
+            throw UnknownApiException("Unknown class $className")
+        }
+    }
+
+    private fun ensureFieldExists(className: String, fieldName: String) {
+        if (classes.findField(className, fieldName) == null) {
+            throw UnknownApiException("Unknown field $className.$fieldName")
+        }
+    }
+
+    private fun ensureMethodExists(
+        className: String,
+        methodName: String,
+        descriptor: String
+    ) {
+        if (classes.findMethod(className, methodName, descriptor) == null) {
+            throw UnknownApiException("Unknown method $className.$methodName$descriptor")
+        }
+    }
+
+    fun setPolicyForClass(className: String, policy: FilterPolicyWithReason) {
+        ensureClassExists(className)
+        mPolicies[getClassKey(className)] = policy
+    }
+
+    override fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason {
+        return mPolicies[getFieldKey(className, fieldName)]
+                ?: super.getPolicyForField(className, fieldName)
+    }
+
+    fun setPolicyForField(className: String, fieldName: String, policy: FilterPolicyWithReason) {
+        ensureFieldExists(className, fieldName)
+        mPolicies[getFieldKey(className, fieldName)] = policy
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            ): FilterPolicyWithReason {
+        return mPolicies[getMethodKey(className, methodName, descriptor)]
+                ?: super.getPolicyForMethod(className, methodName, descriptor)
+    }
+
+    fun setPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            policy: FilterPolicyWithReason,
+            ) {
+        ensureMethodExists(className, methodName, descriptor)
+        mPolicies[getMethodKey(className, methodName, descriptor)] = policy
+    }
+
+    override fun getRenameTo(className: String, methodName: String, descriptor: String): String? {
+        return mRenames[getMethodKey(className, methodName, descriptor)]
+                ?: super.getRenameTo(className, methodName, descriptor)
+    }
+
+    fun setRenameTo(className: String, methodName: String, descriptor: String, toName: String) {
+        ensureMethodExists(className, methodName, descriptor)
+        ensureMethodExists(className, toName, descriptor)
+        mRenames[getMethodKey(className, methodName, descriptor)] = toName
+    }
+
+    override fun getNativeSubstitutionClass(className: String): String? {
+        return mNativeSubstitutionClasses[getClassKey(className)]
+                ?: super.getNativeSubstitutionClass(className)
+    }
+
+    fun setNativeSubstitutionClass(from: String, to: String) {
+        ensureClassExists(from)
+
+        // Native substitute classes may be provided from other jars, so we can't do this check.
+        // ensureClassExists(to)
+        mNativeSubstitutionClasses[getClassKey(from)] = to.toHumanReadableClassName()
+    }
+
+    override fun getClassLoadHook(className: String): String? {
+        return mClassLoadHooks[getClassKey(className)]
+            ?: super.getClassLoadHook(className)
+    }
+
+    fun setClassLoadHook(className: String, methodName: String) {
+        mClassLoadHooks[getClassKey(className)] = methodName.toHumanReadableMethodName()
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepAllClassesFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepAllClassesFilter.kt
new file mode 100644
index 0000000..45dd38d1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepAllClassesFilter.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.filters
+
+/**
+ * An [OutputFilter] that keeps all classes by default. (but none of its members)
+ *
+ * We're not currently using it, but using it *might* make certain things easier. For example, with
+ * this, all classes would at least be loadable.
+ */
+class KeepAllClassesFilter(fallback: OutputFilter) : DelegatingFilter(fallback) {
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        // If the default visibility wouldn't keep it, change it to "keep".
+        val f = super.getPolicyForClass(className)
+        return f.promoteToKeep("keep-all-classes")
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
new file mode 100644
index 0000000..392ee4b
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.hoststubgen.filters
+
+/**
+ * Base class for "filters", which decides what APIs should go to the stub / impl jars.
+ */
+abstract class OutputFilter {
+    /**
+     * Filters are stacked over one another. This fields contains the "outermost" filter in a
+     * filter stack chain.
+     *
+     * Subclasses must use this filter to get a policy, when they need to infer a policy
+     * from the policy of another API.
+     *
+     * For example, [ClassWidePolicyPropagatingFilter] needs to check the policy of the enclosing
+     * class to propagate "class-wide" policies, but when it does so, it can't just use
+     * `this.getPolicyForClass()` because that wouldn't return policies decided by "outer"
+     * filters. Instead, it uses [outermostFilter.getPolicyForClass()].
+     *
+     * Note, [outermostFilter] can be itself, so make sure not to cause infinity recursions when
+     * using it.
+     */
+    open var outermostFilter: OutputFilter = this
+        get() = field
+        set(value) {
+            field = value
+        }
+
+    abstract fun getPolicyForClass(className: String): FilterPolicyWithReason
+
+    abstract fun getPolicyForField(className: String, fieldName: String): FilterPolicyWithReason
+
+    abstract fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String,
+            ): FilterPolicyWithReason
+
+    /**
+     * If a given method is a substitute-from method, return the substitute-to method name.
+     *
+     * The substitute-to and from methods must have the same signature, in the same class.
+     */
+    open fun getRenameTo(className: String, methodName: String, descriptor: String): String? {
+        return null
+    }
+
+    /**
+     * Return a "native substitution class" name for a given class.
+     *
+     * The result will be in a "human readable" form. (e.g. uses '.'s instead of '/'s)
+     *
+     * (which corresponds to @HostSideTestNativeSubstitutionClass of the standard annotations.)
+     */
+    open fun getNativeSubstitutionClass(className: String): String? {
+        return null
+    }
+
+    /**
+     * Return a "class load hook" method name for a given class.
+     *
+     * (which corresponds to @HostSideTestClassLoadHook of the standard annotations.)
+     */
+    open fun getClassLoadHook(className: String): String? {
+        return null
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/StubIntersectingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/StubIntersectingFilter.kt
new file mode 100644
index 0000000..f92a027
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/StubIntersectingFilter.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.asm.ClassNodes
+
+private const val REASON = "demoted, not in intersect jars"
+
+/**
+ * An [OutputFilter] that will restrict what to put in stub to only what shows up in "intersecting
+ * jar" files.
+ *
+ * For example, if the Android public API stub jar is provided, then the HostStubGen's output
+ * stub will be restricted to public APIs.
+ */
+class StubIntersectingFilter(
+        private val errors: HostStubGenErrors,
+        /**
+         * If a class / field / method is not in any of these jars, then we will not put it in
+         * stub.
+         */
+        private val intersectingJars: Map<String, ClassNodes>,
+        fallback: OutputFilter,
+) : DelegatingFilter(fallback) {
+    private inline fun exists(predicate: (ClassNodes) -> Boolean): Boolean {
+        intersectingJars.forEach { entry ->
+            if (predicate(entry.value)) {
+                return true
+            }
+        }
+        return false
+    }
+
+    /**
+     * If [origPolicy] is less than "Stub", then return it as-is.
+     *
+     * Otherwise, call [inStubChecker] to see if the API is in any of [intersectingJars].
+     * If yes, then return [origPolicy] as-is. Otherwise, demote to "Keep".
+     */
+    private fun intersectWithStub(
+            origPolicy: FilterPolicyWithReason,
+            inStubChecker: () -> Boolean,
+    ): FilterPolicyWithReason {
+        if (origPolicy.policy.needsInStub) {
+            // Only check the stub jars, when the class is supposed to be in stub otherwise.
+            if (!inStubChecker()) {
+                return origPolicy.demoteToKeep(REASON)
+            }
+        }
+        return origPolicy
+    }
+
+    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
+        return intersectWithStub(super.getPolicyForClass(className)) {
+            exists { classes -> classes.findClass(className) != null }
+        }
+    }
+
+    override fun getPolicyForField(
+            className: String,
+            fieldName: String
+    ): FilterPolicyWithReason {
+        return intersectWithStub(super.getPolicyForField(className, fieldName)) {
+            exists { classes -> classes.findField(className, fieldName) != null }
+        }
+    }
+
+    override fun getPolicyForMethod(
+            className: String,
+            methodName: String,
+            descriptor: String
+    ): FilterPolicyWithReason {
+        return intersectWithStub(super.getPolicyForMethod(className, methodName, descriptor)) {
+            exists { classes -> classes.findMethod(className, methodName, descriptor) != null }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
new file mode 100644
index 0000000..46546e8
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -0,0 +1,213 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.UserErrorException
+import com.android.hoststubgen.asm.ClassNodes
+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.PrintWriter
+import java.util.Objects
+
+/**
+ * Print a class node as a "keep" policy.
+ */
+fun printAsTextPolicy(pw: PrintWriter, cn: ClassNode) {
+    pw.printf("class %s\t%s\n", cn.name, "keep")
+
+    for (f in cn.fields ?: emptyList()) {
+        pw.printf("  field %s\t%s\n", f.name, "keep")
+    }
+    for (m in cn.methods ?: emptyList()) {
+        pw.printf("  method %s\t%s\t%s\n", m.name, m.desc, "keep")
+    }
+}
+
+/** 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
+}
+
+/**
+ * Exception for a parse error.
+ */
+private class ParseException : Exception, UserErrorException {
+    val hasSourceInfo: Boolean
+
+    constructor(message: String) : super(message) {
+        hasSourceInfo = false
+    }
+
+    constructor(message: String, file: String, line: Int) :
+            super("$message in file $file line $line") {
+        hasSourceInfo = true
+    }
+
+    fun withSourceInfo(filename: String, lineNo: Int): ParseException {
+        if (hasSourceInfo) {
+            return this // Already has source information.
+        } else {
+            return ParseException(this.message ?: "", filename, lineNo)
+        }
+    }
+}
+
+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 ret = InMemoryOutputFilter(classes, fallback)
+
+        var lineNo = 0
+
+        try {
+            BufferedReader(FileReader(filename)).use { reader ->
+                var className = ""
+
+                while (true) {
+                    var line = reader.readLine()
+                    if (line == null) {
+                        break
+                    }
+                    lineNo++
+
+                    line = normalizeTextLine(line)
+
+                    if (line.isEmpty()) {
+                        continue // skip empty lines.
+                    }
+
+                    val fields = line.split(whitespaceRegex).toTypedArray()
+                    when (fields[0].lowercase()) {
+                        "c", "class" -> {
+                            if (fields.size < 3) {
+                                throw ParseException("Class ('c') expects 2 fields.")
+                            }
+                            className = fields[1]
+                            if (fields[2].startsWith("!")) {
+                                // It's a native-substitution.
+                                val toClass = fields[2].substring(1)
+                                ret.setNativeSubstitutionClass(className, toClass)
+                            } else if (fields[2].startsWith("~")) {
+                                // It's a class-load hook
+                                val callback = fields[2].substring(1)
+                                ret.setClassLoadHook(className, callback)
+                            } else {
+                                val policy = parsePolicy(fields[2])
+                                if (!policy.isUsableWithClasses) {
+                                    throw ParseException("Class can't have policy '$policy'")
+                                }
+                                Objects.requireNonNull(className)
+
+                                // TODO: Duplicate check, etc
+                                ret.setPolicyForClass(className, policy.withReason(FILTER_REASON))
+                            }
+                        }
+
+                        "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
+                            ret.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)
+
+                            ret.setPolicyForMethod(className, name, signature,
+                                    policy.withReason(FILTER_REASON))
+                            if (policy.isSubstitute) {
+                                val fromName = fields[3].substring(1)
+
+                                if (fromName == name) {
+                                    throw ParseException(
+                                            "Substitution must have a different name")
+                                }
+
+                                // Set the policy  for the "from" method.
+                                ret.setPolicyForMethod(className, fromName, signature,
+                                        policy.getSubstitutionBasePolicy()
+                                                .withReason(FILTER_REASON))
+
+                                // Keep "from" -> "to" mapping.
+                                ret.setRenameTo(className, fromName, signature, name)
+                            }
+                        }
+
+                        else -> {
+                            throw ParseException("Unknown directive \"${fields[0]}\"")
+                        }
+                    }
+                }
+            }
+        } catch (e: ParseException) {
+            throw e.withSourceInfo(filename, lineNo)
+        }
+        return ret
+    }
+}
+
+private fun parsePolicy(s: String): FilterPolicy {
+    return when (s.lowercase()) {
+        "s", "stub" -> FilterPolicy.Stub
+        "k", "keep" -> FilterPolicy.Keep
+        "t", "throw" -> FilterPolicy.Throw
+        "r", "remove" -> FilterPolicy.Remove
+        "sc", "stubclass" -> FilterPolicy.StubClass
+        "kc", "keepclass" -> FilterPolicy.KeepClass
+        else -> {
+            if (s.startsWith("@")) {
+                FilterPolicy.SubstituteAndStub
+            } else if (s.startsWith("%")) {
+                FilterPolicy.SubstituteAndKeep
+            } else {
+                throw ParseException("Invalid policy \"$s\"")
+            }
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
new file mode 100644
index 0000000..3cf9a1d
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
@@ -0,0 +1,252 @@
+/*
+ * 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.hoststubgen.visitors
+
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.getPackageNameFromClassName
+import com.android.hoststubgen.asm.resolveClassName
+import com.android.hoststubgen.asm.toJvmClassName
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+import com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.FieldVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.util.TraceClassVisitor
+import java.io.PrintWriter
+
+val OPCODE_VERSION = Opcodes.ASM9
+
+abstract class BaseAdapter (
+        protected val classes: ClassNodes,
+        nextVisitor: ClassVisitor,
+        protected val filter: OutputFilter,
+        protected val options: Options,
+) : ClassVisitor(OPCODE_VERSION, nextVisitor) {
+
+    /**
+     * Options to control the behavior.
+     */
+    data class Options (
+            val errors: HostStubGenErrors,
+            val enablePreTrace: Boolean,
+            val enablePostTrace: Boolean,
+            val enableMethodLogging: Boolean,
+            val enableNonStubMethodCallDetection: Boolean,
+    )
+
+    protected lateinit var currentPackageName: String
+    protected lateinit var currentClassName: String
+    protected var nativeSubstitutionClass: String? = null
+    protected lateinit var classPolicy: FilterPolicyWithReason
+
+    /**
+     * Return whether an item with a given policy should be included in the output.
+     */
+    protected abstract fun shouldEmit(policy: FilterPolicy): Boolean
+
+    override fun visit(
+            version: Int,
+            access: Int,
+            name: String,
+            signature: String?,
+            superName: String?,
+            interfaces: Array<String>,
+    ) {
+        super.visit(version, access, name, signature, superName, interfaces)
+        currentClassName = name
+        currentPackageName = getPackageNameFromClassName(name)
+        classPolicy = filter.getPolicyForClass(currentClassName)
+
+        log.d("[%s] visit: %s (package: %s)", this.javaClass.simpleName, name, currentPackageName)
+        log.indent()
+        log.v("Emitting class: %s", name)
+        log.indent()
+
+        filter.getNativeSubstitutionClass(currentClassName)?.let { className ->
+            val fullClassName = resolveClassName(className, currentPackageName).toJvmClassName()
+            log.d("  NativeSubstitutionClass: $fullClassName")
+            if (classes.findClass(fullClassName) == null) {
+                log.w("Native substitution class $fullClassName not found. Class must be " +
+                        "available at runtime.")
+            } else {
+                // If the class exists, it must have a KeepClass policy.
+                if (filter.getPolicyForClass(fullClassName).policy != FilterPolicy.KeepClass) {
+                    // TODO: Use real annotation name.
+                    options.errors.onErrorFound(
+                            "Native substitution class $fullClassName should have @Keep.")
+                }
+            }
+
+            nativeSubstitutionClass = fullClassName
+        }
+        // Inject annotations to generated classes.
+        if (classPolicy.policy.needsInStub) {
+            visitAnnotation(HostStubGenProcessedStubClass.CLASS_DESCRIPTOR, true)
+        }
+        if (classPolicy.policy.needsInImpl) {
+            visitAnnotation(HostStubGenProcessedKeepClass.CLASS_DESCRIPTOR, true)
+        }
+    }
+
+    override fun visitEnd() {
+        log.unindent()
+        log.unindent()
+        super.visitEnd()
+    }
+
+    var skipMemberModificationNestCount = 0
+
+    /**
+     * This method allows writing class members without any modifications.
+     */
+    protected inline fun writeRawMembers(callback: () -> Unit) {
+        skipMemberModificationNestCount++
+        try {
+            callback()
+        } finally {
+            skipMemberModificationNestCount--
+        }
+    }
+
+    override fun visitField(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            value: Any?,
+    ): FieldVisitor? {
+        if (skipMemberModificationNestCount > 0) {
+            return super.visitField(access, name, descriptor, signature, value)
+        }
+        val policy = filter.getPolicyForField(currentClassName, name)
+        log.d("visitField: %s %s [%x] Policy: %s", name, descriptor, access, policy)
+
+        log.withIndent {
+            if (!shouldEmit(policy.policy)) {
+                log.d("Removing %s %s", name, policy)
+                return null
+            }
+
+            log.v("Emitting field: %s %s %s", name, descriptor, policy)
+            return super.visitField(access, name, descriptor, signature, value)
+        }
+    }
+
+    override fun visitMethod(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+    ): MethodVisitor? {
+        if (skipMemberModificationNestCount > 0) {
+            return super.visitMethod(access, name, descriptor, signature, exceptions)
+        }
+        val p = filter.getPolicyForMethod(currentClassName, name, descriptor)
+        log.d("visitMethod: %s%s [%x] [%s] Policy: %s", name, descriptor, access, signature, p)
+
+        log.withIndent {
+            // If it's a substitute-to method, then skip.
+            val policy = filter.getPolicyForMethod(currentClassName, name, descriptor)
+            if (policy.policy.isSubstitute) {
+                log.d("Skipping %s%s %s", name, descriptor, policy)
+                return null
+            }
+            if (!shouldEmit(p.policy)) {
+                log.d("Removing %s%s %s", name, descriptor, policy)
+                return null
+            }
+
+            // Maybe rename the method.
+            val newName: String
+            val substituteTo = filter.getRenameTo(currentClassName, name, descriptor)
+            if (substituteTo != null) {
+                newName = substituteTo
+                log.v("Emitting %s.%s%s as %s %s", currentClassName, name, descriptor,
+                        newName, policy)
+            } else {
+                log.v("Emitting method: %s%s %s", name, descriptor, policy)
+                newName = name
+            }
+
+            // Let subclass update the flag.
+            // But note, we only use it when calling the super's method,
+            // but not for visitMethodInner(), beucase when subclass wants to change access,
+            // it can do so inside visitMethodInner().
+            val newAccess = updateAccessFlags(access, name, descriptor)
+
+            return visitMethodInner(access, newName, descriptor, signature, exceptions, policy,
+                    super.visitMethod(newAccess, newName, descriptor, signature, exceptions))
+        }
+    }
+
+    open fun updateAccessFlags(
+            access: Int,
+            name: String,
+            descriptor: String,
+    ): Int {
+        return access
+    }
+
+    abstract fun visitMethodInner(
+        access: Int,
+        name: String,
+        descriptor: String,
+        signature: String?,
+        exceptions: Array<String>?,
+        policy: FilterPolicyWithReason,
+        superVisitor: MethodVisitor?,
+        ): MethodVisitor?
+
+    companion object {
+        fun getVisitor(
+                classes: ClassNodes,
+                nextVisitor: ClassVisitor,
+                filter: OutputFilter,
+                forImpl: Boolean,
+                options: Options,
+        ): ClassVisitor {
+            var next = nextVisitor
+
+            val verbosePrinter = PrintWriter(log.getVerbosePrintStream())
+
+            // TODO: This doesn't work yet.
+
+            // Inject TraceClassVisitor for debugging.
+            if (options.enablePostTrace) {
+                next = TraceClassVisitor(next, verbosePrinter)
+            }
+            var ret: ClassVisitor
+            if (forImpl) {
+                ret = ImplGeneratingAdapter(classes, next, filter, options)
+            } else {
+                ret = StubGeneratingAdapter(classes, next, filter, options)
+            }
+
+            // Inject TraceClassVisitor for debugging.
+            if (options.enablePreTrace) {
+                ret = TraceClassVisitor(ret, verbosePrinter)
+            }
+            return ret
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
new file mode 100644
index 0000000..8250412
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
@@ -0,0 +1,354 @@
+/*
+ * 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.hoststubgen.visitors
+
+import org.objectweb.asm.AnnotationVisitor
+import org.objectweb.asm.Attribute
+import org.objectweb.asm.Handle
+import org.objectweb.asm.Label
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.TypePath
+
+/**
+ * A method visitor that removes everything from method body.
+ *
+ * To inject a method body, override [visitCode] and create the opcodes there.
+ */
+abstract class BodyReplacingMethodVisitor(
+    access: Int,
+    name: String,
+    descriptor: String,
+    signature: String?,
+    exceptions: Array<String>?,
+    next: MethodVisitor?,
+) : MethodVisitor(OPCODE_VERSION, next) {
+    val isVoid: Boolean
+    val isStatic: Boolean
+
+    init {
+        isVoid = descriptor.endsWith(")V")
+        isStatic = access and Opcodes.ACC_STATIC != 0
+    }
+
+    // Following methods are for things that we need to keep.
+    // Since they're all calling the super method, we can just remove them, but we keep them
+    // just to clarify what we're keeping.
+
+    final override fun visitParameter(
+            name: String?,
+            access: Int
+    ) {
+        super.visitParameter(name, access)
+    }
+
+    final override fun visitAnnotationDefault(): AnnotationVisitor? {
+        return super.visitAnnotationDefault()
+    }
+
+    final override fun visitAnnotation(
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        return super.visitAnnotation(descriptor, visible)
+    }
+
+    final override fun visitTypeAnnotation(
+        typeRef: Int,
+        typePath: TypePath?,
+        descriptor: String?,
+        visible: Boolean
+    ): AnnotationVisitor? {
+        return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible)
+    }
+
+    final override fun visitAnnotableParameterCount(
+            parameterCount: Int,
+            visible: Boolean
+    ) {
+        super.visitAnnotableParameterCount(parameterCount, visible)
+    }
+
+    final override fun visitParameterAnnotation(
+            parameter: Int,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        return super.visitParameterAnnotation(parameter, descriptor, visible)
+    }
+
+    final override fun visitAttribute(attribute: Attribute?) {
+        super.visitAttribute(attribute)
+    }
+
+    override fun visitEnd() {
+        super.visitEnd()
+    }
+
+    /**
+     * Control when to emit the code. We use this to ignore all visitXxx method calls caused by
+     * the original method, so we'll remove all the original code.
+     *
+     * Only when visitXxx methods are called from [emitNewCode], we pass-through to the base class,
+     * so the body will be generated.
+     *
+     * (See also https://asm.ow2.io/asm4-guide.pdf section 3.2.1 about the MethovVisitor
+     * call order.)
+     */
+    var emitCode = false
+
+    final override fun visitCode() {
+        super.visitCode()
+
+        try {
+            emitCode = true
+
+            emitNewCode()
+        } finally {
+            emitCode = false
+        }
+    }
+
+    /**
+     * Subclass must implement it and emit code, and call [visitMaxs] at the end.
+     */
+    abstract fun emitNewCode()
+
+    final override fun visitMaxs(
+            maxStack: Int,
+            maxLocals: Int
+    ) {
+        if (emitCode) {
+            super.visitMaxs(maxStack, maxLocals)
+        }
+    }
+
+    // Following methods are called inside a method body, and we don't want to
+    // emit any of them, so they are all no-op.
+
+    final override fun visitFrame(
+            type: Int,
+            numLocal: Int,
+            local: Array<out Any>?,
+            numStack: Int,
+            stack: Array<out Any>?
+    ) {
+        if (emitCode) {
+            super.visitFrame(type, numLocal, local, numStack, stack)
+        }
+    }
+
+    final override fun visitInsn(opcode: Int) {
+        if (emitCode) {
+            super.visitInsn(opcode)
+        }
+    }
+
+    final override fun visitIntInsn(
+            opcode: Int,
+            operand: Int
+    ) {
+        if (emitCode) {
+            super.visitIntInsn(opcode, operand)
+        }
+    }
+
+    final override fun visitVarInsn(
+            opcode: Int,
+            varIndex: Int
+    ) {
+        if (emitCode) {
+            super.visitVarInsn(opcode, varIndex)
+        }
+    }
+
+    final override fun visitTypeInsn(
+            opcode: Int,
+            type: String?
+    ) {
+        if (emitCode) {
+            super.visitTypeInsn(opcode, type)
+        }
+    }
+
+    final override fun visitFieldInsn(
+            opcode: Int,
+            owner: String?,
+            name: String?,
+            descriptor: String?
+    ) {
+        if (emitCode) {
+            super.visitFieldInsn(opcode, owner, name, descriptor)
+        }
+    }
+
+    final override fun visitMethodInsn(
+            opcode: Int,
+            owner: String?,
+            name: String?,
+            descriptor: String?,
+            isInterface: Boolean
+    ) {
+        if (emitCode) {
+            super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
+        }
+    }
+
+    final override fun visitInvokeDynamicInsn(
+            name: String?,
+            descriptor: String?,
+            bootstrapMethodHandle: Handle?,
+            vararg bootstrapMethodArguments: Any?
+    ) {
+        if (emitCode) {
+            super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle,
+                    *bootstrapMethodArguments)
+        }
+    }
+
+    final override fun visitJumpInsn(
+            opcode: Int,
+            label: Label?
+    ) {
+        if (emitCode) {
+            super.visitJumpInsn(opcode, label)
+        }
+    }
+
+    final override fun visitLabel(label: Label?) {
+        if (emitCode) {
+            super.visitLabel(label)
+        }
+    }
+
+    final override fun visitLdcInsn(value: Any?) {
+        if (emitCode) {
+            super.visitLdcInsn(value)
+        }
+    }
+
+    final override fun visitIincInsn(
+            varIndex: Int,
+            increment: Int
+    ) {
+        if (emitCode) {
+            super.visitIincInsn(varIndex, increment)
+        }
+    }
+
+    final override fun visitTableSwitchInsn(
+            min: Int,
+            max: Int,
+            dflt: Label?,
+            vararg labels: Label?
+    ) {
+        if (emitCode) {
+            super.visitTableSwitchInsn(min, max, dflt, *labels)
+        }
+    }
+
+    final override fun visitLookupSwitchInsn(
+            dflt: Label?,
+            keys: IntArray?,
+            labels: Array<out Label>?
+    ) {
+        if (emitCode) {
+            super.visitLookupSwitchInsn(dflt, keys, labels)
+        }
+    }
+
+    final override fun visitMultiANewArrayInsn(
+            descriptor: String?,
+            numDimensions: Int
+    ) {
+        if (emitCode) {
+            super.visitMultiANewArrayInsn(descriptor, numDimensions)
+        }
+    }
+
+    final override fun visitInsnAnnotation(
+            typeRef: Int,
+            typePath: TypePath?,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        if (emitCode) {
+            return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible)
+        }
+        return null
+    }
+
+    final override fun visitTryCatchBlock(
+            start: Label?,
+            end: Label?,
+            handler: Label?,
+            type: String?
+    ) {
+        if (emitCode) {
+            super.visitTryCatchBlock(start, end, handler, type)
+        }
+    }
+
+    final override fun visitTryCatchAnnotation(
+            typeRef: Int,
+            typePath: TypePath?,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        if (emitCode) {
+            return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible)
+        }
+        return null
+    }
+
+    final override fun visitLocalVariable(
+            name: String?,
+            descriptor: String?,
+            signature: String?,
+            start: Label?,
+            end: Label?,
+            index: Int
+    ) {
+        if (emitCode) {
+            super.visitLocalVariable(name, descriptor, signature, start, end, index)
+        }
+    }
+
+    final override fun visitLocalVariableAnnotation(
+            typeRef: Int,
+            typePath: TypePath?,
+            start: Array<out Label>?,
+            end: Array<out Label>?,
+            index: IntArray?,
+            descriptor: String?,
+            visible: Boolean
+    ): AnnotationVisitor? {
+        if (emitCode) {
+            return super.visitLocalVariableAnnotation(
+                    typeRef, typePath, start, end, index, descriptor, visible)
+        }
+        return null
+    }
+
+    final override fun visitLineNumber(
+            line: Int,
+            start: Label?
+    ) {
+        if (emitCode) {
+            super.visitLineNumber(line, start)
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
new file mode 100644
index 0000000..ac06886
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -0,0 +1,370 @@
+/*
+ * 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.hoststubgen.visitors
+
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
+import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.isVisibilityPrivateOrPackagePrivate
+import com.android.hoststubgen.asm.writeByteCodeToPushArguments
+import com.android.hoststubgen.asm.writeByteCodeToReturn
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.hosthelper.HostTestUtils
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+import org.objectweb.asm.Type
+
+/**
+ * An adapter that generates the "impl" class file from an input class file.
+ */
+class ImplGeneratingAdapter(
+        classes: ClassNodes,
+        nextVisitor: ClassVisitor,
+        filter: OutputFilter,
+        options: Options,
+) : BaseAdapter(classes, nextVisitor, filter, options) {
+
+    override fun shouldEmit(policy: FilterPolicy): Boolean {
+        return policy.needsInImpl
+    }
+
+    private var classLoadHookMethod: String? = null
+
+    override fun visit(
+        version: Int,
+        access: Int,
+        name: String,
+        signature: String?,
+        superName: String?,
+        interfaces: Array<String>
+    ) {
+        super.visit(version, access, name, signature, superName, interfaces)
+
+        classLoadHookMethod = filter.getClassLoadHook(currentClassName)
+
+        // classLoadHookMethod is non-null, then we need to inject code to call it
+        // in the class initializer.
+        // If the target class already has a class initializer, then we need to inject code to it.
+        // Otherwise, we need to create one.
+
+        classLoadHookMethod?.let { callback ->
+            log.d("  ClassLoadHook: $callback")
+            if (!classes.hasClassInitializer(currentClassName)) {
+                injectClassLoadHook(callback)
+            }
+        }
+    }
+
+    private fun injectClassLoadHook(callback: String) {
+        writeRawMembers {
+            // Create a class initializer to call onClassLoaded().
+            // Each class can only have at most one class initializer, but the base class
+            // StaticInitMerger will merge it with the existing one, if any.
+            visitMethod(
+                Opcodes.ACC_PRIVATE or Opcodes.ACC_STATIC,
+                "<clinit>",
+                "()V",
+                null,
+                null
+            )!!.let { mv ->
+                // Method prologue
+                mv.visitCode()
+
+                writeClassLoadHookCall(mv)
+                mv.visitInsn(Opcodes.RETURN)
+
+                // Method epilogue
+                mv.visitMaxs(0, 0)
+                mv.visitEnd()
+            }
+        }
+    }
+
+    private fun writeClassLoadHookCall(mv: MethodVisitor) {
+        // First argument: the class type.
+        mv.visitLdcInsn(Type.getType("L" + currentClassName + ";"))
+
+        // Second argument: method name
+        mv.visitLdcInsn(classLoadHookMethod)
+
+        // Call HostTestUtils.onClassLoaded().
+        mv.visitMethodInsn(
+            Opcodes.INVOKESTATIC,
+            HostTestUtils.CLASS_INTERNAL_NAME,
+            "onClassLoaded",
+            "(Ljava/lang/Class;Ljava/lang/String;)V",
+            false
+        )
+    }
+
+    override fun updateAccessFlags(
+            access: Int,
+            name: String,
+            descriptor: String,
+    ): Int {
+        if ((access and Opcodes.ACC_NATIVE) != 0 && nativeSubstitutionClass != null) {
+            return access and Opcodes.ACC_NATIVE.inv()
+        }
+        return access
+    }
+
+    override fun visitMethodInner(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            policy: FilterPolicyWithReason,
+            superVisitor: MethodVisitor?,
+    ): MethodVisitor? {
+        // Inject method log, if needed.
+        var innerVisitor = superVisitor
+
+        //  If method logging is enabled, inject call to the logging method.
+        if (options.enableMethodLogging) {
+            innerVisitor = LogInjectingMethodAdapter(
+                    access,
+                    name,
+                    descriptor,
+                    signature,
+                    exceptions,
+                    innerVisitor,
+                    )
+        }
+
+        // If this class already has a class initializer and a class load hook is needed, then
+        // we inject code.
+        if (classLoadHookMethod != null &&
+            name == CLASS_INITIALIZER_NAME &&
+            descriptor == CLASS_INITIALIZER_DESC) {
+            innerVisitor = ClassLoadHookInjectingMethodAdapter(
+                access,
+                name,
+                descriptor,
+                signature,
+                exceptions,
+                innerVisitor,
+            )
+        }
+
+        // If non-stub method call detection is enabled, then inject a call to the checker.
+        if (options.enableNonStubMethodCallDetection && doesMethodNeedNonStubCallCheck(
+                access, name, descriptor, policy) ) {
+            innerVisitor = NonStubMethodCallDetectingAdapter(
+                    access,
+                    name,
+                    descriptor,
+                    signature,
+                    exceptions,
+                    innerVisitor,
+            )
+        }
+
+        log.withIndent {
+            if ((access and Opcodes.ACC_NATIVE) != 0 && nativeSubstitutionClass != null) {
+                log.v("Rewriting native method...")
+                return NativeSubstitutingMethodAdapter(
+                        access, name, descriptor, signature, exceptions, innerVisitor)
+            }
+            if (policy.policy == FilterPolicy.Throw) {
+                log.v("Making method throw...")
+                return ThrowingMethodAdapter(
+                        access, name, descriptor, signature, exceptions, innerVisitor)
+            }
+        }
+
+        return innerVisitor
+    }
+
+    fun doesMethodNeedNonStubCallCheck(
+            access: Int,
+            name: String,
+            descriptor: String,
+            policy: FilterPolicyWithReason,
+    ): Boolean {
+        // If a method is in the stub, then no need to check.
+        if (policy.policy.needsInStub) {
+            return false
+        }
+        // If a method is private or package-private, no need to check.
+        // Technically test code can use framework package name, so it's a bit too lenient.
+        if (isVisibilityPrivateOrPackagePrivate(access)) {
+            return false
+        }
+        // TODO: If the method overrides a method that's accessible by tests, then we shouldn't
+        // do the check. (e.g. overrides a stub method or java standard method.)
+
+        return true
+    }
+
+    /**
+     * A method adapter that replaces the method body with a HostTestUtils.onThrowMethodCalled()
+     * call.
+     */
+    private inner class ThrowingMethodAdapter(
+            access: Int,
+            val name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
+        override fun emitNewCode() {
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "onThrowMethodCalled",
+                    "()V",
+                    false)
+
+            // We still need a RETURN opcode for the return type.
+            // For now, let's just inject a `throw`.
+            visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException")
+            visitInsn(Opcodes.DUP)
+            visitLdcInsn("Unreachable")
+            visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException",
+                    "<init>", "(Ljava/lang/String;)V", false)
+            visitInsn(Opcodes.ATHROW)
+
+            // visitMaxs(3, if (isStatic) 0 else 1)
+            visitMaxs(0, 0) // We let ASM figure them out.
+        }
+    }
+
+    /**
+     * A method adapter that replaces a native method call with a call to the "native substitution"
+     * class.
+     */
+    private inner class NativeSubstitutingMethodAdapter(
+            access: Int,
+            private val name: String,
+            private val descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+
+            throw RuntimeException("NativeSubstitutingMethodVisitor should be called on " +
+                    " native method, where visitCode() shouldn't be called.")
+        }
+
+        override fun visitEnd() {
+            writeByteCodeToPushArguments(descriptor, this)
+
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    nativeSubstitutionClass,
+                    name,
+                    descriptor,
+                    false)
+
+            writeByteCodeToReturn(descriptor, this)
+
+            visitMaxs(99, 0) // We let ASM figure them out.
+            super.visitEnd()
+        }
+    }
+
+    /**
+     * A method adapter that injects a call to HostTestUtils.logMethodCall() to every method.
+     *
+     * Note, when the target method is a constructor, it may contain calls to `super(...)` or
+     * `this(...)`. The logging code will be injected *before* such calls.
+     */
+    private inner class LogInjectingMethodAdapter(
+            access: Int,
+            val name: String,
+            val descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+            visitLdcInsn(currentClassName)
+            visitLdcInsn(name)
+            visitLdcInsn(descriptor)
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "logMethodCall",
+                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+                    false)
+        }
+    }
+
+    /**
+     * Inject a class load hook call.
+     */
+    private inner class ClassLoadHookInjectingMethodAdapter(
+        access: Int,
+        val name: String,
+        val descriptor: String,
+        signature: String?,
+        exceptions: Array<String>?,
+        next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+
+            writeClassLoadHookCall(this)
+        }
+    }
+
+    /**
+     * A method adapter that detects calls to non-stub methods.
+     */
+    private inner class NonStubMethodCallDetectingAdapter(
+            access: Int,
+            val name: String,
+            val descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : MethodVisitor(OPCODE_VERSION, next) {
+        override fun visitCode() {
+            super.visitCode()
+
+            // First three arguments to HostTestUtils.onNonStubMethodCalled().
+            visitLdcInsn(currentClassName)
+            visitLdcInsn(name)
+            visitLdcInsn(descriptor)
+
+            // Call: HostTestUtils.getStackWalker().getCallerClass().
+            // This push the caller Class in the stack.
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "getStackWalker",
+                    "()Ljava/lang/StackWalker;",
+                    false)
+            visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+                    "java/lang/StackWalker",
+                    "getCallerClass",
+                    "()Ljava/lang/Class;",
+                    false)
+
+            // Then call onNonStubMethodCalled().
+            visitMethodInsn(Opcodes.INVOKESTATIC,
+                    HostTestUtils.CLASS_INTERNAL_NAME,
+                    "onNonStubMethodCalled",
+                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V",
+                    false)
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt
new file mode 100644
index 0000000..37e2a88
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/StubGeneratingAdapter.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.visitors
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.filters.FilterPolicyWithReason
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.log
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.MethodVisitor
+import org.objectweb.asm.Opcodes
+
+/**
+ * An adapter that generates the "impl" class file from an input class file.
+ */
+class StubGeneratingAdapter(
+        classes: ClassNodes,
+        nextVisitor: ClassVisitor,
+        filter: OutputFilter,
+        options: Options,
+) : BaseAdapter(classes, nextVisitor, filter, options) {
+
+    override fun shouldEmit(policy: FilterPolicy): Boolean {
+        return policy.needsInStub
+    }
+
+    override fun visitMethodInner(
+            access: Int,
+            name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            policy: FilterPolicyWithReason,
+            superVisitor: MethodVisitor?,
+    ): MethodVisitor? {
+        return StubMethodVisitor(access, name, descriptor, signature, exceptions, superVisitor)
+    }
+
+    private inner class StubMethodVisitor(
+            access: Int,
+            val name: String,
+            descriptor: String,
+            signature: String?,
+            exceptions: Array<String>?,
+            next: MethodVisitor?
+    ) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
+        override fun emitNewCode() {
+            log.d("  Generating stub method for $currentClassName.$name")
+
+            // Inject the following code:
+            //   throw new RuntimeException("Stub!");
+
+            /*
+                NEW java/lang/RuntimeException
+                DUP
+                LDC "not supported on host side"
+                INVOKESPECIAL java/lang/RuntimeException.<init> (Ljava/lang/String;)V
+                ATHROW
+                MAXSTACK = 3
+                MAXLOCALS = 2 <- 1 for this, 1 for return value.
+             */
+            visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException")
+            visitInsn(Opcodes.DUP)
+            visitLdcInsn("Stub!")
+            visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException",
+                    "<init>", "(Ljava/lang/String;)V", false)
+            visitInsn(Opcodes.ATHROW)
+            visitMaxs(0, 0) // We let ASM figure them out.
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-framework/Android.bp
new file mode 100644
index 0000000..2b91cc1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+build = ["AndroidHostTest.bp"]
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
new file mode 100644
index 0000000..e7fb2de
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidHostTest.bp
@@ -0,0 +1,44 @@
+// 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.
+
+// Add `build = ["AndroidHostTest.bp"]` to Android.bp to include this file.
+
+// Compile the test jar, using 2 rules.
+// 1. Build the test against the stub.
+java_library_host {
+    name: "HostStubGenTest-framework-test-host-test-lib",
+    defaults: ["hosttest-with-framework-all-hidden-api-test-lib-defaults"],
+    srcs: [
+        "src/**/*.java",
+    ],
+    static_libs: [
+        "junit",
+        "truth-prebuilt",
+        "mockito",
+
+        // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
+        "platform-test-annotations",
+        "hoststubgen-annotations",
+    ],
+}
+
+// 2. Link the above module with necessary runtime dependencies, so it can be executed stand-alone.
+java_test_host {
+    name: "HostStubGenTest-framework-all-test-host-test",
+    defaults: ["hosttest-with-framework-all-hidden-api-test-defaults"],
+    static_libs: [
+        "HostStubGenTest-framework-test-host-test-lib",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tools/hoststubgen/hoststubgen/test-framework/AndroidTest-host.xml b/tools/hoststubgen/hoststubgen/test-framework/AndroidTest-host.xml
new file mode 100644
index 0000000..f35dcf6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/AndroidTest-host.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- [Ravenwood] Copied from $ANDROID_BUILD_TOP/cts/hostsidetests/devicepolicy/AndroidTest.xml  -->
+<configuration description="CtsContentTestCases host-side test">
+    <option name="test-suite-tag" value="ravenwood" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+
+    <test class="com.android.tradefed.testtype.IsolatedHostTest" >
+        <option name="jar" value="HostStubGenTest-framework-all-test-host-test.jar" />
+    </test>
+</configuration>
diff --git a/tools/hoststubgen/hoststubgen/test-framework/README.md b/tools/hoststubgen/hoststubgen/test-framework/README.md
new file mode 100644
index 0000000..20e2f87
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/README.md
@@ -0,0 +1,27 @@
+# HostStubGen: real framework test
+
+This directory contains tests against the actual framework.jar code. The tests were
+copied from somewhere else in the android tree. We use this directory to quickly run existing
+tests.
+
+## How to run
+
+- With `atest`. This is the proper way to run it, but it may fail due to atest's known problems.
+
+  See the top level README.md on why `--no-bazel-mode` is needed (for now).
+
+```
+$ atest --no-bazel-mode HostStubGenTest-framework-test-host-test
+```
+
+- With `run-ravenwood-test`
+
+```
+$ run-ravenwood-test HostStubGenTest-framework-test-host-test
+```
+
+- Advanced option: `run-test-without-atest.sh` runs the test without using `atest` or `run-ravenwood-test`
+
+```
+$ ./run-test-without-atest.sh
+```
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-framework/run-test-without-atest.sh b/tools/hoststubgen/hoststubgen/test-framework/run-test-without-atest.sh
new file mode 100755
index 0000000..cfc06a1
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/run-test-without-atest.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# 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.
+
+# Run HostStubGenTest-framework-test-host-test directly with JUnit.
+# (without using atest.)
+
+source "${0%/*}"/../../common.sh
+
+
+# Options:
+# -v enable verbose log
+# -d enable debugger
+
+verbose=0
+debug=0
+while getopts "vd" opt; do
+  case "$opt" in
+    v) verbose=1 ;;
+    d) debug=1 ;;
+  esac
+done
+shift $(($OPTIND - 1))
+
+
+if (( $verbose )) ; then
+  JAVA_OPTS="$JAVA_OPTS -verbose:class"
+fi
+
+if (( $debug )) ; then
+  JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8700"
+fi
+
+#=======================================
+module=HostStubGenTest-framework-all-test-host-test
+module_jar=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/$module/$module.jar
+run m $module
+
+out=out
+
+rm -fr $out
+mkdir -p $out
+
+
+# Copy and extract the relevant jar files so we can look into them.
+run cp \
+    $module_jar \
+    $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/framework-all-hidden-api-host/linux_glibc_common/gen/*.jar \
+    $out
+
+run extract $out/*.jar
+
+# Result is the number of failed tests.
+result=0
+
+
+# This suite runs all tests in the JAR.
+tests=(com.android.hoststubgen.hosthelper.HostTestSuite)
+
+# Uncomment this to run a specific test.
+# tests=(com.android.hoststubgen.frameworktest.LogTest)
+
+
+for class in ${tests[@]} ; do
+  echo "Running $class ..."
+
+  run cd "${module_jar%/*}"
+  run $JAVA $JAVA_OPTS \
+      -cp $module_jar \
+      org.junit.runner.JUnitCore \
+      $class || result=$(( $result + 1 ))
+done
+
+exit $result
diff --git a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
new file mode 100644
index 0000000..62bbf48
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/ArrayMapTest.java
@@ -0,0 +1,737 @@
+/*
+ * 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.hoststubgen.frameworktest;
+
+// [ravewnwood] Copied from cts/, and commented out unsupported stuff.
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+/**
+ * Some basic tests for {@link android.util.ArrayMap}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ArrayMapTest {
+    static final boolean DEBUG = false;
+
+    static final int OP_ADD = 1;
+    static final int OP_REM = 2;
+
+    static int[] OPS = new int[]{
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD, OP_ADD,
+            OP_ADD, OP_ADD, OP_ADD,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM,
+            OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM, OP_REM,
+    };
+
+    static int[] KEYS = new int[]{
+            // General adding and removing.
+            -1, 1900, 600, 200, 1200, 1500, 1800, 100, 1900,
+            2100, 300, 800, 600, 1100, 1300, 2000, 1000, 1400,
+            600, -1, 1900, 600, 300, 2100, 200, 800, 800,
+            1800, 1500, 1300, 1100, 2000, 1400, 1000, 1200, 1900,
+
+            // Shrink when removing item from end.
+            100, 200, 300, 400, 500, 600, 700, 800, 900,
+            900, 800, 700, 600, 500, 400, 300, 200, 100,
+
+            // Shrink when removing item from middle.
+            100, 200, 300, 400, 500, 600, 700, 800, 900,
+            900, 800, 700, 600, 500, 400, 200, 300, 100,
+
+            // Shrink when removing item from front.
+            100, 200, 300, 400, 500, 600, 700, 800, 900,
+            900, 800, 700, 600, 500, 400, 100, 200, 300,
+
+            // Test hash collisions.
+            105, 106, 108, 104, 102, 102, 107, 5, 205,
+            4, 202, 203, 3, 5, 101, 109, 200, 201,
+            0, -1, 100,
+            106, 108, 104, 102, 103, 105, 107, 101, 109,
+            -1, 100, 0,
+            4, 5, 3, 5, 200, 203, 202, 201, 205,
+    };
+
+    public static class ControlledHash implements Parcelable {
+        final int mValue;
+
+        ControlledHash(int value) {
+            mValue = value;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o == null) {
+                return false;
+            }
+            return mValue == ((ControlledHash)o).mValue;
+        }
+
+        @Override
+        public final int hashCode() {
+            return mValue/100;
+        }
+
+        @Override
+        public final String toString() {
+            return Integer.toString(mValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mValue);
+        }
+
+        public static final Parcelable.Creator<ControlledHash> CREATOR
+                = new Parcelable.Creator<ControlledHash>() {
+            public ControlledHash createFromParcel(Parcel in) {
+                return new ControlledHash(in.readInt());
+            }
+
+            public ControlledHash[] newArray(int size) {
+                return new ControlledHash[size];
+            }
+        };
+    }
+
+    private static boolean compare(Object v1, Object v2) {
+        if (v1 == null) {
+            return v2 == null;
+        }
+        if (v2 == null) {
+            return false;
+        }
+        return v1.equals(v2);
+    }
+
+    private static void compareMaps(HashMap map, ArrayMap array) {
+        if (map.size() != array.size()) {
+            fail("Bad size: expected " + map.size() + ", got " + array.size());
+        }
+
+        Set<Entry> mapSet = map.entrySet();
+        for (Map.Entry entry : mapSet) {
+            Object expValue = entry.getValue();
+            Object gotValue = array.get(entry.getKey());
+            if (!compare(expValue, gotValue)) {
+                fail("Bad value: expected " + expValue + ", got " + gotValue
+                        + " at key " + entry.getKey());
+            }
+        }
+
+        for (int i = 0; i < array.size(); i++) {
+            Object gotValue = array.valueAt(i);
+            Object key = array.keyAt(i);
+            Object expValue = map.get(key);
+            if (!compare(expValue, gotValue)) {
+                fail("Bad value: expected " + expValue + ", got " + gotValue
+                        + " at key " + key);
+            }
+        }
+
+        if (map.entrySet().hashCode() != array.entrySet().hashCode()) {
+            fail("Entry set hash codes differ: map=0x"
+                    + Integer.toHexString(map.entrySet().hashCode()) + " array=0x"
+                    + Integer.toHexString(array.entrySet().hashCode()));
+        }
+
+        if (!map.entrySet().equals(array.entrySet())) {
+            fail("Failed calling equals on map entry set against array set");
+        }
+
+        if (!array.entrySet().equals(map.entrySet())) {
+            fail("Failed calling equals on array entry set against map set");
+        }
+
+        if (map.keySet().hashCode() != array.keySet().hashCode()) {
+            fail("Key set hash codes differ: map=0x"
+                    + Integer.toHexString(map.keySet().hashCode()) + " array=0x"
+                    + Integer.toHexString(array.keySet().hashCode()));
+        }
+
+        if (!map.keySet().equals(array.keySet())) {
+            fail("Failed calling equals on map key set against array set");
+        }
+
+        if (!array.keySet().equals(map.keySet())) {
+            fail("Failed calling equals on array key set against map set");
+        }
+
+        if (!map.keySet().containsAll(array.keySet())) {
+            fail("Failed map key set contains all of array key set");
+        }
+
+        if (!array.keySet().containsAll(map.keySet())) {
+            fail("Failed array key set contains all of map key set");
+        }
+
+        if (!array.containsAll(map.keySet())) {
+            fail("Failed array contains all of map key set");
+        }
+
+        if (!map.entrySet().containsAll(array.entrySet())) {
+            fail("Failed map entry set contains all of array entry set");
+        }
+
+        if (!array.entrySet().containsAll(map.entrySet())) {
+            fail("Failed array entry set contains all of map entry set");
+        }
+    }
+
+    private static void validateArrayMap(ArrayMap array) {
+        Set<Map.Entry> entrySet = array.entrySet();
+        int index = 0;
+        Iterator<Entry> entryIt = entrySet.iterator();
+        while (entryIt.hasNext()) {
+            Map.Entry entry = entryIt.next();
+            Object value = entry.getKey();
+            Object realValue = array.keyAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map entry set: expected key " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            value = entry.getValue();
+            realValue = array.valueAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map entry set: expected value " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            index++;
+        }
+
+        index = 0;
+        Set keySet = array.keySet();
+        Iterator keyIt = keySet.iterator();
+        while (keyIt.hasNext()) {
+            Object value = keyIt.next();
+            Object realValue = array.keyAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map key set: expected key " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            index++;
+        }
+
+        index = 0;
+        Collection valueCol = array.values();
+        Iterator valueIt = valueCol.iterator();
+        while (valueIt.hasNext()) {
+            Object value = valueIt.next();
+            Object realValue = array.valueAt(index);
+            if (!compare(realValue, value)) {
+                fail("Bad array map value col: expected value " + realValue
+                        + ", got " + value + " at index " + index);
+            }
+            index++;
+        }
+    }
+
+    private static void compareBundles(Bundle bundle1, Bundle bundle2) {
+        Set<String> keySet1 = bundle1.keySet();
+        Iterator<String> iterator1 = keySet1.iterator();
+        while (iterator1.hasNext()) {
+            String key = iterator1.next();
+            int value1 = bundle1.getInt(key);
+            if (bundle2.get(key) == null) {
+                fail("Bad Bundle: bundle2 didn't have expected key " + key);
+            }
+            int value2 = bundle2.getInt(key);
+            if (value1 != value2) {
+                fail("Bad Bundle: at key key " + key + " expected " + value1 + ", got " + value2);
+            }
+        }
+        Set<String> keySet2 = bundle2.keySet();
+        Iterator<String> iterator2 = keySet2.iterator();
+        while (iterator2.hasNext()) {
+            String key = iterator2.next();
+            if (bundle1.get(key) == null) {
+                fail("Bad Bundle: bundle1 didn't have expected key " + key);
+            }
+            int value1 = bundle1.getInt(key);
+            int value2 = bundle2.getInt(key);
+            if (value1 != value2) {
+                fail("Bad Bundle: at key key " + key + " expected " + value1 + ", got " + value2);
+            }
+        }
+    }
+
+    private static void dump(Map map, ArrayMap array) {
+        Log.e("test", "HashMap of " + map.size() + " entries:");
+        Set<Map.Entry> mapSet = map.entrySet();
+        for (Map.Entry entry : mapSet) {
+            Log.e("test", "    " + entry.getKey() + " -> " + entry.getValue());
+        }
+        Log.e("test", "ArrayMap of " + array.size() + " entries:");
+        for (int i = 0; i < array.size(); i++) {
+            Log.e("test", "    " + array.keyAt(i) + " -> " + array.valueAt(i));
+        }
+    }
+
+    private static void dump(ArrayMap map1, ArrayMap map2) {
+        Log.e("test", "ArrayMap of " + map1.size() + " entries:");
+        for (int i = 0; i < map1.size(); i++) {
+            Log.e("test", "    " + map1.keyAt(i) + " -> " + map1.valueAt(i));
+        }
+        Log.e("test", "ArrayMap of " + map2.size() + " entries:");
+        for (int i = 0; i < map2.size(); i++) {
+            Log.e("test", "    " + map2.keyAt(i) + " -> " + map2.valueAt(i));
+        }
+    }
+
+    private static void dump(Bundle bundle1, Bundle bundle2) {
+        Log.e("test", "First Bundle of " + bundle1.size() + " entries:");
+        Set<String> keys1 = bundle1.keySet();
+        for (String key : keys1) {
+            Log.e("test", "    " + key + " -> " + bundle1.get(key));
+        }
+        Log.e("test", "Second Bundle of " + bundle2.size() + " entries:");
+        Set<String> keys2 = bundle2.keySet();
+        for (String key : keys2) {
+            Log.e("test", "    " + key + " -> " + bundle2.get(key));
+        }
+    }
+
+    @Test
+    public void testBasicArrayMap() {
+        HashMap<ControlledHash, Integer> hashMap = new HashMap<>();
+        ArrayMap<ControlledHash, Integer> arrayMap = new ArrayMap<>();
+        Bundle bundle = new Bundle();
+
+        for (int i = 0; i < OPS.length; i++) {
+            Integer oldHash;
+            Integer oldArray;
+            ControlledHash key = KEYS[i] < 0 ? null : new ControlledHash(KEYS[i]);
+            String strKey = KEYS[i] < 0 ? null : Integer.toString(KEYS[i]);
+            switch (OPS[i]) {
+                case OP_ADD:
+                    if (DEBUG) Log.i("test", "Adding key: " + key);
+                    oldHash = hashMap.put(key, i);
+                    oldArray = arrayMap.put(key, i);
+                    bundle.putInt(strKey, i);
+                    break;
+                case OP_REM:
+                    if (DEBUG) Log.i("test", "Removing key: " + key);
+                    oldHash = hashMap.remove(key);
+                    oldArray = arrayMap.remove(key);
+                    bundle.remove(strKey);
+                    break;
+                default:
+                    fail("Bad operation " + OPS[i] + " @ " + i);
+                    return;
+            }
+            if (!compare(oldHash, oldArray)) {
+                String msg = "Bad result: expected " + oldHash + ", got " + oldArray;
+                Log.e("test", msg);
+                dump(hashMap, arrayMap);
+                fail(msg);
+            }
+            try {
+                validateArrayMap(arrayMap);
+            } catch (Throwable e) {
+                Log.e("test", e.getMessage());
+                dump(hashMap, arrayMap);
+                throw e;
+            }
+            try {
+                compareMaps(hashMap, arrayMap);
+            } catch (Throwable e) {
+                Log.e("test", e.getMessage());
+                dump(hashMap, arrayMap);
+                throw e;
+            }
+            Parcel parcel = Parcel.obtain();
+            bundle.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            Bundle bundle2 = parcel.readBundle();
+            try {
+                compareBundles(bundle, bundle2);
+            } catch (Throwable e) {
+                Log.e("test", e.getMessage());
+                dump(bundle, bundle2);
+                throw e;
+            }
+        }
+
+        arrayMap.put(new ControlledHash(50000), 100);
+        ControlledHash lookup = new ControlledHash(50000);
+        Iterator<ControlledHash> it = arrayMap.keySet().iterator();
+        while (it.hasNext()) {
+            if (it.next().equals(lookup)) {
+                it.remove();
+            }
+        }
+        if (arrayMap.containsKey(lookup)) {
+            String msg = "Bad map iterator: didn't remove test key";
+            Log.e("test", msg);
+            dump(hashMap, arrayMap);
+            fail(msg);
+        }
+    }
+
+    @Test
+    public void testCopyArrayMap() {
+        // map copy constructor test
+        ArrayMap newMap = new ArrayMap<Integer, String>();
+        for (int i = 0; i < 10; ++i) {
+            newMap.put(i, String.valueOf(i));
+        }
+        ArrayMap mapCopy = new ArrayMap(newMap);
+        if (!compare(mapCopy, newMap)) {
+            String msg = "ArrayMap copy constructor failure: expected " +
+                    newMap + ", got " + mapCopy;
+            Log.e("test", msg);
+            dump(newMap, mapCopy);
+            fail(msg);
+            return;
+        }
+    }
+
+    @Test
+    public void testEqualsArrayMap() {
+        ArrayMap<Integer, String> map1 = new ArrayMap<>();
+        ArrayMap<Integer, String> map2 = new ArrayMap<>();
+        HashMap<Integer, String> map3 = new HashMap<>();
+        if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
+            fail("ArrayMap equals failure for empty maps " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+
+        for (int i = 0; i < 10; ++i) {
+            String value = String.valueOf(i);
+            map1.put(i, value);
+            map2.put(i, value);
+            map3.put(i, value);
+        }
+        if (!compare(map1, map2) || !compare(map1, map3) || !compare(map3, map2)) {
+            fail("ArrayMap equals failure for populated maps " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+
+        map1.remove(0);
+        if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) {
+            fail("ArrayMap equals failure for map size " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+
+        map1.put(0, "-1");
+        if (compare(map1, map2) || compare(map1, map3) || compare(map3, map1)) {
+            fail("ArrayMap equals failure for map contents " + map1 + ", " +
+                    map2 + ", " + map3);
+        }
+    }
+
+//    /**
+//     * Test creating a malformed array map with duplicated keys and that we will catch this when
+//     * unparcelling.
+//     */
+//    @Test
+//    public void testDuplicateKeys() throws NoSuchMethodException,
+//            InvocationTargetException, IllegalAccessException, NoSuchFieldException {
+//        ArrayMap<String, Object> map1 = new ArrayMap(2);
+//
+//        Method appendMethod = ArrayMap.class.getMethod("append", Object.class, Object.class);
+//        appendMethod.invoke(map1, Integer.toString(100000), "foo");
+//        appendMethod.invoke(map1, Integer.toString(100000), "bar");
+//
+//        // Now parcel/unparcel, and verify we get the expected error.
+//        Parcel parcel = Parcel.obtain();
+//        Method writeArrayMapMethod = Parcel.class.getMethod("writeArrayMap", ArrayMap.class);
+//        writeArrayMapMethod.invoke(parcel, map1);
+//        parcel.setDataPosition(0);
+//        ArrayMap<String, Object> map2 = new ArrayMap(2);
+//
+//        try {
+//            Parcel.class.getMethod("readArrayMap", ArrayMap.class, ClassLoader.class).invoke(
+//                    parcel, map2, null);
+//        } catch (InvocationTargetException e) {
+//            Throwable cause = e.getCause();
+//            if (cause instanceof IllegalArgumentException) {
+//                // Good!
+//                return;
+//            }
+//            throw e;
+//        }
+//
+//        String msg = "Didn't throw expected IllegalArgumentException";
+//        Log.e("test", msg);
+//        dump(map1, map2);
+//        fail(msg);
+//    }
+
+    private static void checkEntrySetToArray(ArrayMap<?, ?> testMap) {
+        try {
+            testMap.entrySet().toArray();
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+
+        try {
+            Map.Entry<?, ?>[] entries = new Map.Entry[20];
+            testMap.entrySet().toArray(entries);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    // http://b/32294038, Test ArrayMap.entrySet().toArray()
+    @Test
+    public void testEntrySetArray() {
+        // Create
+        ArrayMap<Integer, String> testMap = new ArrayMap<>();
+
+        // Test empty
+        checkEntrySetToArray(testMap);
+
+        // Test non-empty
+        for (int i = 0; i < 10; ++i) {
+            testMap.put(i, String.valueOf(i));
+        }
+        checkEntrySetToArray(testMap);
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<Map.Entry<String, String>> expectedEntriesToIterate = new HashSet<>(Arrays.asList(
+                entryOf("key 1", "value 1"),
+                entryOf("key 2", "value 2")
+        ));
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+
+        // Assert iteration over the expected two entries in any order
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> firstEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(firstEntry));
+
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> secondEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(secondEntry));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    private static <K, V> Map.Entry<K, V> entryOf(K key, V value) {
+        return new AbstractMap.SimpleEntry<>(key, value);
+    }
+
+    private static <K, V> Map.Entry<K, V> copyOf(Map.Entry<K, V> entry) {
+        return entryOf(entry.getKey(), entry.getValue());
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_keySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedKeysToIterate = new HashSet<>(Arrays.asList("key 1", "key 2"));
+        Iterator<String> iterator = map.keySet().iterator();
+
+        // Assert iteration over the expected two keys in any order
+        assertTrue(iterator.hasNext());
+        String firstKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(firstKey));
+
+        assertTrue(iterator.hasNext());
+        String secondKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(secondKey));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_valuesIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedValuesToIterate = new HashSet<>(Arrays.asList("value 1", "value 2"));
+        Iterator<String> iterator = map.values().iterator();
+
+        // Assert iteration over the expected two values in any order
+        assertTrue(iterator.hasNext());
+        String firstValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(firstValue));
+
+        assertTrue(iterator.hasNext());
+        String secondValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(secondValue));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    @Test
+    public void testForEach() {
+        ArrayMap<String, Integer> map = new ArrayMap<>();
+
+        for (int i = 0; i < 50; ++i) {
+            map.put(Integer.toString(i), i * 10);
+        }
+
+        // Make sure forEach goes through all of the elements.
+        HashMap<String, Integer> seen = new HashMap<>();
+        map.forEach(seen::put);
+        compareMaps(seen, map);
+    }
+
+    /**
+     * The entrySet Iterator returns itself from each call to {@code next()}. This is unusual
+     * behavior for {@link Iterator#next()}; this test ensures that any future change to this
+     * behavior is deliberate.
+     */
+    @Test
+    public void testUnusualBehavior_eachEntryIsSameAsIterator_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+
+        assertSame(iterator, iterator.next());
+        assertSame(iterator, iterator.next());
+    }
+
+    @SuppressWarnings("SelfEquals")
+    @Test
+    public void testUnusualBehavior_equalsThrowsAfterRemove_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+        iterator.next();
+        iterator.remove();
+        try {
+            iterator.equals(iterator);
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    private static <T> void assertEqualsBothWays(T a, T b) {
+        assertEquals(a, b);
+        assertEquals(b, a);
+        assertEquals(a.hashCode(), b.hashCode());
+    }
+
+    @Test
+    public void testRemoveAll() {
+        final ArrayMap<Integer, String> map = new ArrayMap<>();
+        for (Integer i : Arrays.asList(0, 1, 2, 3, 4, 5)) {
+            map.put(i, i.toString());
+        }
+
+        final ArrayMap<Integer, String> expectedMap = new ArrayMap<>();
+        for (Integer i : Arrays.asList(2, 4)) {
+            expectedMap.put(i, String.valueOf(i));
+        }
+        map.removeAll(Arrays.asList(0, 1, 3, 5, 6));
+        if (!compare(map, expectedMap)) {
+            fail("ArrayMap removeAll failure, expect " + expectedMap + ", but " + map);
+        }
+
+        map.removeAll(Collections.emptyList());
+        if (!compare(map, expectedMap)) {
+            fail("ArrayMap removeAll failure for empty maps, expect " + expectedMap + ", but " +
+                    map);
+        }
+
+        map.removeAll(Arrays.asList(2, 4));
+        if (!map.isEmpty()) {
+            fail("ArrayMap removeAll failure, expect empty, but " + map);
+        }
+    }
+
+    @Test
+    public void testReplaceAll() {
+        final ArrayMap<Integer, Integer> map = new ArrayMap<>();
+        final ArrayMap<Integer, Integer> expectedMap = new ArrayMap<>();
+        final BiFunction<Integer, Integer, Integer> function = (k, v) -> 2 * v;
+        for (Integer i : Arrays.asList(0, 1, 2, 3, 4, 5)) {
+            map.put(i, i);
+            expectedMap.put(i, 2 * i);
+        }
+
+        map.replaceAll(function);
+        if (!compare(map, expectedMap)) {
+            fail("ArrayMap replaceAll failure, expect " + expectedMap + ", but " + map);
+        }
+    }
+}
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
new file mode 100644
index 0000000..56544b4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-framework/src/com/android/hoststubgen/frameworktest/LogTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.frameworktest;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.util.Log;
+import android.util.Slog;
+
+import org.junit.Test;
+
+/**
+ * Some basic tests for {@link android.util.Log}.
+ */
+public class LogTest {
+    @Test
+    public void testBasicLogging() {
+        Log.v("TAG", "Test v log");
+        Log.d("TAG", "Test d log");
+        Log.i("TAG", "Test i log");
+        Log.w("TAG", "Test w log");
+        Log.e("TAG", "Test e log");
+
+        Slog.v("TAG", "Test v slog");
+        Slog.d("TAG", "Test d slog");
+        Slog.i("TAG", "Test i slog");
+        Slog.w("TAG", "Test w slog");
+        Slog.e("TAG", "Test e slog");
+    }
+
+    @Test
+    public void testNativeMethods() {
+        assertThat(Log.isLoggable("mytag", Log.INFO)).isTrue();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
new file mode 100644
index 0000000..8c76a61
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp
@@ -0,0 +1,141 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// A library that simulates framework-all.jar
+java_library {
+    name: "hoststubgen-test-tiny-framework",
+    installable: true,
+    host_supported: true,
+    srcs: ["tiny-framework/src/**/*.java"],
+    static_libs: [
+        "hoststubgen-annotations",
+    ],
+}
+
+// Create stub/impl jars from "hoststubgen-test-tiny-framework", using the following 3 rules.
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host",
+    defaults: ["hoststubgen-command-defaults"],
+    cmd: hoststubgen_common_options +
+        "--in-jar $(location :hoststubgen-test-tiny-framework) " +
+        "--policy-override-file $(location policy-override-tiny-framework.txt) ",
+    srcs: [
+        ":hoststubgen-test-tiny-framework",
+        "policy-override-tiny-framework.txt",
+    ],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-stub",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host{host_stub.jar}",
+    ],
+    out: [
+        "host_stub.jar",
+    ],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-impl",
+    cmd: "cp $(in) $(out)",
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host{host_impl.jar}",
+    ],
+    out: [
+        "host_impl.jar",
+    ],
+}
+
+// Compile the test jar, using 2 rules.
+// 1. Build the test against the stub.
+java_library_host {
+    name: "hoststubgen-test-tiny-test-lib",
+    srcs: ["tiny-test/src/**/*.java"],
+
+    libs: [
+        "hoststubgen-test-tiny-framework-host-stub",
+    ],
+    static_libs: [
+        "junit",
+        "truth-prebuilt",
+
+        // http://cs/h/googleplex-android/platform/superproject/main/+/main:platform_testing/libraries/annotations/src/android/platform/test/annotations/
+        "platform-test-annotations",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// 2. Link "hoststubgen-test-tiny-test-lib" with necessary runtime dependencies, so it can be
+// executed stand-alone.
+java_test_host {
+    name: "hoststubgen-test-tiny-test",
+    test_config: "AndroidTest-host.xml",
+    static_libs: [
+        "hoststubgen-test-tiny-test-lib",
+        "hoststubgen-helper-runtime",
+        "hoststubgen-test-tiny-framework-host-impl",
+    ],
+    test_suites: ["general-tests"],
+}
+
+// Dump the original, stub and impl jars as text files.
+// We use them in test-and-update-golden.sh.
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-orig-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework",
+    ],
+    out: [
+        "01-hoststubgen-test-tiny-framework-orig-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-stub-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-stub",
+    ],
+    out: [
+        "02-hoststubgen-test-tiny-framework-host-stub-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+java_genrule_host {
+    name: "hoststubgen-test-tiny-framework-host-impl-dump",
+    defaults: ["hoststubgen-jar-dump-defaults"],
+    srcs: [
+        ":hoststubgen-test-tiny-framework-host-impl",
+    ],
+    out: [
+        "03-hoststubgen-test-tiny-framework-host-impl-dump.txt",
+    ],
+    visibility: ["//visibility:private"],
+}
+
+// Run it with `atest`. Compare the dump of the jar files to the golden output.
+python_test_host {
+    name: "tiny-framework-dump-test",
+    srcs: [
+        "tiny-framework-dump-test.py",
+    ],
+    data: [
+        "golden-output/*.txt",
+    ],
+    java_data: [
+        "hoststubgen-test-tiny-framework-host-stub-dump",
+        "hoststubgen-test-tiny-framework-host-impl-dump",
+        "hoststubgen-test-tiny-framework-orig-dump",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml b/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml
new file mode 100644
index 0000000..84aad69
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/AndroidTest-host.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- [Ravenwood] Copied from $ANDROID_BUILD_TOP/cts/hostsidetests/devicepolicy/AndroidTest.xml  -->
+<configuration description="HostStubGen sample test">
+    <option name="test-suite-tag" value="ravenwood" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+    <option name="config-descriptor:metadata" key="parameter" value="no_foldable_states" />
+
+    <test class="com.android.tradefed.testtype.IsolatedHostTest" >
+        <option name="jar" value="hoststubgen-test-tiny-test.jar" />
+    </test>
+</configuration>
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
new file mode 100644
index 0000000..f3c0450
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/README.md
@@ -0,0 +1,27 @@
+# HostStubGen: tiny-framework test
+
+This directory contains a small classes that "simulates" framework.jar, and tests against it.
+
+This test doesn't use the actual android framework code.
+
+## How to run
+
+- With `atest`. This is the proper way to run it, but `atest` has known problems that may
+  affect the result. If you see weird problems, try the next `run-ravenwood-test` command.
+
+```
+$ atest hoststubgen-test-tiny-test
+```
+
+- With `run-ravenwood-test` should work too. This is the proper way to run it.
+
+```
+$ run-ravenwood-test hoststubgen-test-tiny-test
+```
+
+- `run-test-manually.sh` also run the test, but it builds the stub/impl jars and the test without
+  using the build system. This is useful for debugging the tool.
+
+```
+$ ./run-test-manually.sh
+```
\ No newline at end of file
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
new file mode 100755
index 0000000..4d58869
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/diff-and-update-golden.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+# 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.
+
+help() {
+  cat <<'EOF'
+
+  diff-and-update-golden.sh [OPTIONS]
+
+    Compare the generated jar files from tiny-framework to the "golden" files.
+
+  OPTIONS:
+    -u: Update the golden files.
+
+    -3: Run `meld` to compare original, stub and impl jar files in 3-way diff.
+        This is useful to visualize the exact differences between 3 jar files.
+
+    -2: Run `meld` to compare original <-> impl, and impl <-> stub as two different diffs.
+EOF
+}
+
+source "${0%/*}"/../../common.sh
+
+SCRIPT_NAME="${0##*/}"
+
+GOLDEN_DIR=golden-output
+mkdir -p $GOLDEN_DIR
+
+DIFF_CMD=${DIFF:-diff -u --ignore-blank-lines --ignore-space-change}
+
+update=0
+three_way=0
+two_way=0
+while getopts "u32" opt; do
+case "$opt" in
+    u)
+        update=1
+        ;;
+    3)
+        three_way=1
+        ;;
+    2)
+        two_way=1
+        ;;
+    '?')
+        help
+        exit 1
+        ;;
+esac
+done
+shift $(($OPTIND - 1))
+
+
+# Build the dump files, which are the input of this test.
+run m tiny-framework-dump-test
+
+
+# Get the path to the generate text files. (not the golden files.)
+# We get them from $OUT/module-info.json
+
+files=(
+$(python3 -c '
+import sys
+import os
+import json
+
+with open(sys.argv[1], "r") as f:
+    data = json.load(f)
+
+    # Equivalent to: jq -r '.["tiny-framework-dump-test"]["installed"][]'
+    for path in data["tiny-framework-dump-test"]["installed"]:
+
+      if "golden-output" in path:
+        continue
+      if path.endswith(".txt"):
+        print(os.getenv("ANDROID_BUILD_TOP") + "/" + path)
+' $OUT/module-info.json)
+)
+
+# Next, compare each file and update them in $GOLDEN_DIR
+
+any_file_changed=0
+
+for file in ${files[*]} ; do
+  name=$(basename $file)
+  echo "# Checking $name ..."
+
+  file_changed=0
+  if run $DIFF_CMD $GOLDEN_DIR/$name $file; then
+    : # No diff
+  else
+    file_changed=1
+    any_file_changed=1
+  fi
+
+  if (( $update && $file_changed )) ; then
+    echo "# Updating $name ..."
+    run cp $file $GOLDEN_DIR/$name
+  fi
+done
+
+if (( $three_way )) ; then
+  echo "# Running 3-way diff with meld..."
+  run meld ${files[*]} &
+fi
+
+if (( $two_way )) ; then
+  echo "# Running meld..."
+  run meld --diff ${files[0]} ${files[1]} --diff ${files[1]} ${files[2]}
+fi
+
+if (( $any_file_changed == 0 )) ; then
+  echo "$SCRIPT_NAME: Success: no changes detected."
+  exit 0
+else
+  if (( $update )) ; then
+    echo "$SCRIPT_NAME: Warning: golden files have been updated."
+    exit 2
+  else
+    echo "$SCRIPT_NAME: Failure: changes detected. See above diff for the details."
+    exit 3
+  fi
+fi
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
new file mode 100644
index 0000000..1aa4859
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -0,0 +1,1671 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+  Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+  Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class
+  Compiled from "HostSideTestNativeSubstitutionClass.java"
+public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestNativeSubstitutionClass.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+  Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRemove
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestStub.class
+  Compiled from "HostSideTestStub.java"
+public interface android.hosttest.annotation.HostSideTestStub extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStub.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+  Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestSubstitute
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+  Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestThrow
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+  Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassStub.class
+  Compiled from "HostSideTestWholeClassStub.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassStub extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassStub.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  1: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/tests/HostSideTestSuppress.class
+  Compiled from "HostSideTestSuppress.java"
+public interface android.hosttest.annotation.tests.HostSideTestSuppress extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/tests/HostSideTestSuppress
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestSuppress.java"
+RuntimeVisibleAnnotations:
+  0: #x(#x=[e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl;
+
+  public static int getOneKeep();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkCallerCheck.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck;
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+         3: ireturn
+      LineNumberTable:
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+         3: ireturn
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
+  Compiled from "TinyFrameworkClassAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 10, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                  // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       6     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       4     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestRemove
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String not supported on host side
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0      10     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public static int nativeAddThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestStub
+  1: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 10, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                  // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String not supported on host side
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0      10     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+      1: #x(#x=s#x)
+        android.hosttest.annotation.HostSideTestSubstitute(
+          suffix="_host"
+        )
+
+  public static int nativeAddThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 2
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: getstatic     #x                  // Field sLoadedClasses:Ljava/util/Set;
+         3: aload_0
+         4: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+         9: pop
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class java/util/HashSet
+         3: dup
+         4: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+         7: putstatic     #x                  // Field sLoadedClasses:Ljava/util/Set;
+        10: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
+  Compiled from "TinyFrameworkClassWithInitializer.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 2
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: putstatic     #x                  // Field sInitialized:Z
+         4: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeInvisibleAnnotations:
+  0: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  1: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=0
+         0: new           #x                  // class java/lang/IllegalStateException
+         3: dup
+         4: ldc           #x                  // String Inner exception
+         6: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+         9: athrow
+        10: astore_0
+        11: new           #x                 // class java/lang/RuntimeException
+        14: dup
+        15: ldc           #x                 // String Outer exception
+        17: aload_0
+        18: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        21: athrow
+      Exception table:
+         from    to  target type
+             0    10    10   Class java/lang/Exception
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0     e   Ljava/lang/Exception;
+      StackMapTable: number_of_entries = 1
+        frame_type = 74 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 10, attributes: 1
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                  // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String not supported on host side
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0      10     1 value   I
+
+  public int addTwo_host(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public static native int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static int addThree_host(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 5, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+  public static native int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iload_0
+         1: invokestatic  #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         4: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0   arg   I
+
+  public static native long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         0: lload_0
+         1: lload_2
+         2: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         5: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  arg1   J
+            0       6     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  1: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+  Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 2
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0   arg   I
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         0: lload_0
+         1: lload_2
+         2: ladd
+         3: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  arg1   J
+            0       4     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 1, methods: 3, attributes: 5
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                  // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+            0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iconst_1
+         1: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iconst_2
+         1: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 1, methods: 3, attributes: 5
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                  // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+            0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iconst_3
+         1: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iconst_4
+         1: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 3
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iload_1
+         6: putfield      #x                  // Field value:I
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+            0      10     1     x   I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                  // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         9: aload_0
+        10: iconst_5
+        11: putfield      #x                 // Field value:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+            0      15     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 5
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: bipush        7
+         2: invokestatic  #x                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+         5: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+}
+Signature: #x                          // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: bipush        6
+         7: putfield      #x                  // Field value:I
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 1, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+         5: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+            0       6     1     x   I
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+InnerClasses:
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 4
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                  // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: new           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         8: dup
+         9: aload_0
+        10: invokespecial #x                  // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        13: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        16: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      17     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         3: dup
+         4: aload_0
+         5: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         8: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       9     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+         7: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        10: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;          // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                 // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
new file mode 100644
index 0000000..6e1528a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -0,0 +1,837 @@
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 4
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+InnerClasses:
+  private static #x= #x of #x;           // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 5
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
+  Compiled from "TinyFrameworkClassAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 5, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestStub
+  1: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 8, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
+  Compiled from "TinyFrameworkClassWithInitializer.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  1: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 5, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 5, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static native int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static native long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=4, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  1: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+InnerClasses:
+  public static #x= #x of #x;            // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 1, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+InnerClasses:
+  public #x= #x of #x;                   // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+InnerClasses:
+  public static #x= #x of #x;            // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+InnerClasses:
+  public static #x= #x of #x;            // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;            // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=3, locals=0, args_size=0
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #x                 // String Stub!
+         6: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+}
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
new file mode 100644
index 0000000..5672e9c
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -0,0 +1,1774 @@
+## Class: android/hosttest/annotation/HostSideTestClassLoadHook.class
+  Compiled from "HostSideTestClassLoadHook.java"
+public interface android.hosttest.annotation.HostSideTestClassLoadHook extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestKeep.class
+  Compiled from "HostSideTestKeep.java"
+public interface android.hosttest.annotation.HostSideTestKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class
+  Compiled from "HostSideTestNativeSubstitutionClass.java"
+public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String value();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestNativeSubstitutionClass.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestRemove.class
+  Compiled from "HostSideTestRemove.java"
+public interface android.hosttest.annotation.HostSideTestRemove extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestRemove
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRemove.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestStub.class
+  Compiled from "HostSideTestStub.java"
+public interface android.hosttest.annotation.HostSideTestStub extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestStub.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestSubstitute.class
+  Compiled from "HostSideTestSubstitute.java"
+public interface android.hosttest.annotation.HostSideTestSubstitute extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestSubstitute
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 1, attributes: 2
+  public abstract java.lang.String suffix();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
+}
+SourceFile: "HostSideTestSubstitute.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestThrow.class
+  Compiled from "HostSideTestThrow.java"
+public interface android.hosttest.annotation.HostSideTestThrow extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestThrow
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestThrow.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x,e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassKeep.class
+  Compiled from "HostSideTestWholeClassKeep.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassKeep
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassKeep.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: android/hosttest/annotation/HostSideTestWholeClassStub.class
+  Compiled from "HostSideTestWholeClassStub.java"
+public interface android.hosttest.annotation.HostSideTestWholeClassStub extends java.lang.annotation.Annotation
+  minor version: 0
+  major version: 61
+  flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+  this_class: #x                          // android/hosttest/annotation/HostSideTestWholeClassStub
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestWholeClassStub.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+  1: #x(#x=[e#x.#x])
+    java.lang.annotation.Target(
+      value=[Ljava/lang/annotation/ElementType;.TYPE]
+    )
+  2: #x(#x=e#x.#x)
+    java.lang.annotation.Retention(
+      value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 4
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl;
+
+  public static int getOneKeep();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=0, args_size=0
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+         2: ldc           #x                 // String getOneKeep
+         4: ldc           #x                 // String ()I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_1
+        16: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public static int getOneStub();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: iconst_1
+         1: ireturn
+      LineNumberTable:
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+InnerClasses:
+  private static #x= #x of #x;           // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
+  Compiled from "TinyFrameworkCallerCheck.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 5
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck;
+
+  public static int getOne_withCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+         3: ireturn
+      LineNumberTable:
+
+  public static int getOne_noCheck();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+         3: ireturn
+      LineNumberTable:
+}
+InnerClasses:
+  private static #x= #x of #x;          // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
+SourceFile: "TinyFrameworkCallerCheck.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.class
+  Compiled from "TinyFrameworkClassAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         2: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         4: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         7: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                 // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       6     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         2: ldc           #x                 // String addOneInner
+         4: ldc           #x                 // String (I)I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iload_1
+        16: iconst_1
+        17: iadd
+        18: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+           15       4     1 value   I
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestKeep
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+            0       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+         2: ldc           #x                 // String unsupportedMethod
+         4: ldc           #x                 // String ()Ljava/lang/String;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        18: new           #x                 // class java/lang/RuntimeException
+        21: dup
+        22: ldc           #x                 // String Unreachable
+        24: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        27: athrow
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestThrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
+    RuntimeInvisibleAnnotations:
+      0: #x()
+        android.hosttest.annotation.HostSideTestStub
+}
+SourceFile: "TinyFrameworkClassAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestStub
+  1: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.class
+  Compiled from "TinyFrameworkClassClassWideAnnotations.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 3, methods: 8, attributes: 3
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int remove;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassClassWideAnnotations();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                 // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_1
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public void toBeRemoved(java.lang.String);
+    descriptor: (Ljava/lang/String;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: new           #x                 // class java/lang/RuntimeException
+         3: dup
+         4: invokespecial #x                 // Method java/lang/RuntimeException."<init>":()V
+         7: athrow
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       8     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       8     1   foo   Ljava/lang/String;
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+            0       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: ldc           #x                 // String This value shouldn\'t be seen on the host side.
+         2: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       3     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
+}
+SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
+  Compiled from "TinyFrameworkClassLoadHook.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 3, attributes: 3
+  public static final java.util.Set<java.lang.Class<?>> sLoadedClasses;
+    descriptor: Ljava/util/Set;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/Set<Ljava/lang/Class<*>;>;
+
+  private com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook();
+    descriptor: ()V
+    flags: (0x0002) ACC_PRIVATE
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook;
+
+  public static void onClassLoaded(java.lang.Class<?>);
+    descriptor: (Ljava/lang/Class;)V
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: getstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+         3: aload_0
+         4: invokeinterface #x,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+         9: pop
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class;
+      LocalVariableTypeTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0 clazz   Ljava/lang/Class<*>;
+    Signature: #x                          // (Ljava/lang/Class<*>;)V
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class java/util/HashSet
+         3: dup
+         4: invokespecial #x                 // Method java/util/HashSet."<init>":()V
+         7: putstatic     #x                 // Field sLoadedClasses:Ljava/util/Set;
+        10: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassLoadHook.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
+  Compiled from "TinyFrameworkClassWithInitializer.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 3
+  public static boolean sInitialized;
+    descriptor: Z
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithInitializer();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+         2: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         4: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         7: iconst_1
+         8: putstatic     #x                 // Field sInitialized:Z
+        11: return
+      LineNumberTable:
+}
+SourceFile: "TinyFrameworkClassWithInitializer.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestClassLoadHook(
+      value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
+    )
+  1: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
+  Compiled from "TinyFrameworkExceptionTester.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 2, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTester();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester;
+
+  public static int testException();
+    descriptor: ()I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=0
+         0: new           #x                 // class java/lang/IllegalStateException
+         3: dup
+         4: ldc           #x                 // String Inner exception
+         6: invokespecial #x                 // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+         9: athrow
+        10: astore_0
+        11: new           #x                 // class java/lang/RuntimeException
+        14: dup
+        15: ldc           #x                 // String Outer exception
+        17: aload_0
+        18: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+        21: athrow
+      Exception table:
+         from    to  target type
+             0    10    10   Class java/lang/Exception
+      StackMapTable: number_of_entries = 1
+        frame_type = 74 /* same_locals_1_stack_item */
+          stack = [ class java/lang/Exception ]
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           11      11     0     e   Ljava/lang/Exception;
+}
+SourceFile: "TinyFrameworkExceptionTester.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
+  Compiled from "TinyFrameworkForTextPolicy.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 8, attributes: 2
+  public int stub;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public int keep;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  private static {};
+    descriptor: ()V
+    flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: ldc           #x                  // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         2: ldc           #x                 // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+         4: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+         7: return
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iconst_1
+         6: putfield      #x                 // Field stub:I
+         9: aload_0
+        10: iconst_2
+        11: putfield      #x                 // Field keep:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+
+  public int addOne(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokevirtual #x                 // Method addOneInner:(I)I
+         5: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       6     1 value   I
+
+  public int addOneInner(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=2, args_size=2
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         2: ldc           #x                 // String addOneInner
+         4: ldc           #x                 // String (I)I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iload_1
+        16: iconst_1
+        17: iadd
+        18: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+           15       4     1 value   I
+
+  public int addTwo(int);
+    descriptor: (I)I
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: iload_1
+         1: iconst_2
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+            0       4     1 value   I
+
+  public static int nativeAddThree(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: iload_0
+         1: iconst_3
+         2: iadd
+         3: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       4     0 value   I
+
+  public java.lang.String unsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+         2: ldc           #x                 // String unsupportedMethod
+         4: ldc           #x                 // String ()Ljava/lang/String;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+        18: new           #x                 // class java/lang/RuntimeException
+        21: dup
+        22: ldc           #x                 // String Unreachable
+        24: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        27: athrow
+
+  public java.lang.String visibleButUsesUnsupportedMethod();
+    descriptor: ()Ljava/lang/String;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokevirtual #x                 // Method unsupportedMethod:()Ljava/lang/String;
+         4: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy;
+}
+SourceFile: "TinyFrameworkForTextPolicy.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
+  Compiled from "TinyFrameworkNative.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 5, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iload_0
+         1: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         4: ireturn
+
+  public static int nativeAddTwo_should_be_like_this(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=1, locals=1, args_size=1
+         0: iload_0
+         1: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+         4: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0   arg   I
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         0: lload_0
+         1: lload_2
+         2: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         5: lreturn
+
+  public static long nativeLongPlus_should_be_like_this(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         0: lload_0
+         1: lload_2
+         2: invokestatic  #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+         5: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  arg1   J
+            0       6     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+  1: #x(#x=s#x)
+    android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+      value="TinyFrameworkNative_host"
+    )
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
+  Compiled from "TinyFrameworkNative_host.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 0, methods: 3, attributes: 3
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         2: ldc           #x                 // String <init>
+         4: ldc           #x                 // String ()V
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokespecial #x                 // Method java/lang/Object."<init>":()V
+        19: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host;
+
+  public static int nativeAddTwo(int);
+    descriptor: (I)I
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         2: ldc           #x                 // String nativeAddTwo
+         4: ldc           #x                 // String (I)I
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iload_0
+        16: iconst_2
+        17: iadd
+        18: ireturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0   arg   I
+
+  public static long nativeLongPlus(long, long);
+    descriptor: (JJ)J
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=4, locals=4, args_size=2
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+         2: ldc           #x                 // String nativeLongPlus
+         4: ldc           #x                 // String (JJ)J
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: lload_0
+        16: lload_2
+        17: ladd
+        18: lreturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       4     0  arg1   J
+           15       4     2  arg2   J
+}
+SourceFile: "TinyFrameworkNative_host.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassKeep
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 1, methods: 3, attributes: 6
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+            0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_1
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_2
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+EnclosingMethod: #x.#x                 // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 1, methods: 3, attributes: 6
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0000)
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+            0      10     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_3
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: iconst_4
+        16: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4;
+}
+InnerClasses:
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 1, attributes: 4
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: iload_1
+         6: putfield      #x                 // Field value:I
+         9: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      10     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass;
+            0      10     1     x   I
+}
+InnerClasses:
+  public static #x= #x of #x;            // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 1, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0;
+    descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$InnerClass(com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses);
+    descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: aload_1
+         2: putfield      #x                 // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+         5: aload_0
+         6: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         9: aload_0
+        10: iconst_5
+        11: putfield      #x                 // Field value:I
+        14: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      15     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass;
+            0      15     1 this$0   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+}
+InnerClasses:
+  public #x= #x of #x;                   // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1 extends java.lang.Object implements java.util.function.Supplier<java.lang.Integer>
+  minor version: 0
+  major version: 61
+  flags: (0x0020) ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  super_class: #x                         // java/lang/Object
+  interfaces: 1, fields: 0, methods: 3, attributes: 6
+  com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass$1();
+    descriptor: ()V
+    flags: (0x0000)
+    Code:
+      stack=1, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Integer get();
+    descriptor: ()Ljava/lang/Integer;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Integer;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: bipush        7
+        17: invokestatic  #x                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+        20: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+
+  public java.lang.Object get();
+    descriptor: ()Ljava/lang/Object;
+    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: ldc           #x                 // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         2: ldc           #x                 // String get
+         4: ldc           #x                 // String ()Ljava/lang/Object;
+         6: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+         9: invokevirtual #x                 // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+        12: invokestatic  #x                 // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+        15: aload_0
+        16: invokevirtual #x                 // Method get:()Ljava/lang/Integer;
+        19: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+           15       5     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1;
+}
+InnerClasses:
+  public static #x= #x of #x;          // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                     // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+EnclosingMethod: #x.#x                // com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass.getSupplier_static
+Signature: #x                           // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 1, methods: 2, attributes: 5
+  public int value;
+    descriptor: I
+    flags: (0x0001) ACC_PUBLIC
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$StaticNestedClass();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: bipush        6
+         7: putfield      #x                 // Field value:I
+        10: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      11     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+}
+InnerClasses:
+  public static #x= #x of #x;            // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass extends com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$BaseClass
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  super_class: #x                         // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  interfaces: 0, fields: 0, methods: 1, attributes: 4
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$SubClass(int);
+    descriptor: (I)V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=2, locals=2, args_size=2
+         0: aload_0
+         1: iload_1
+         2: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+         5: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       6     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass;
+            0       6     1     x   I
+}
+InnerClasses:
+  public static #x= #x of #x;            // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;            // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
+  Compiled from "TinyFrameworkNestedClasses.java"
+public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses
+  minor version: 0
+  major version: 61
+  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
+  this_class: #x                          // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  super_class: #x                         // java/lang/Object
+  interfaces: 0, fields: 2, methods: 4, attributes: 5
+  public final java.util.function.Supplier<java.lang.Integer> mSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static final java.util.function.Supplier<java.lang.Integer> sSupplier;
+    descriptor: Ljava/util/function/Supplier;
+    flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #x                          // Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses();
+    descriptor: ()V
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=4, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #x                 // Method java/lang/Object."<init>":()V
+         4: aload_0
+         5: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+         8: dup
+         9: aload_0
+        10: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+        13: putfield      #x                 // Field mSupplier:Ljava/util/function/Supplier;
+        16: return
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0      17     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+
+  public java.util.function.Supplier<java.lang.Integer> getSupplier();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0001) ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+         3: dup
+         4: aload_0
+         5: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+         8: areturn
+      LineNumberTable:
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       9     0  this   Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
+    descriptor: ()Ljava/util/function/Supplier;
+    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+         7: areturn
+      LineNumberTable:
+    Signature: #x                          // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
+
+  static {};
+    descriptor: ()V
+    flags: (0x0008) ACC_STATIC
+    Code:
+      stack=2, locals=0, args_size=0
+         0: new           #x                 // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+         3: dup
+         4: invokespecial #x                 // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+         7: putstatic     #x                 // Field sSupplier:Ljava/util/function/Supplier;
+        10: return
+      LineNumberTable:
+}
+InnerClasses:
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  public static #x= #x of #x;           // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public static #x= #x of #x;           // StaticNestedClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  public #x= #x of #x;                  // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
+  #x;                                    // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+SourceFile: "TinyFrameworkNestedClasses.java"
+RuntimeVisibleAnnotations:
+  0: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
+  1: #x()
+    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
+RuntimeInvisibleAnnotations:
+  0: #x()
+    android.hosttest.annotation.HostSideTestWholeClassStub
+NestMembers:
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+  com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
new file mode 100644
index 0000000..079d2a8
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt
@@ -0,0 +1,17 @@
+class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy	stub
+  field stub	stub
+  field keep	keep
+  # field remove	remove # Implicitly remove
+  method <init>	()V	            stub
+  method addOne	(I)I	        stub
+  method addOneInner	(I)I	keep
+  method toBeRemoved	(Ljava/lang/String;)V	remove
+  method addTwo	(I)I	        @addTwo_host
+  # method addTwo_host	(I)I	# used as a substitute
+  method nativeAddThree	(I)I	@addThree_host
+  # method addThree_host	(I)I	# used as a substitute
+  method unsupportedMethod	()Ljava/lang/String;	throw
+  method visibleButUsesUnsupportedMethod	()Ljava/lang/String;	stub
+
+# Class load hook
+class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy	~com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
new file mode 100755
index 0000000..fd48646
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+# 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.
+
+
+source "${0%/*}"/../../common.sh
+
+# This scripts run the "tiny-framework" test, but does most stuff from the command line, using
+# the native java and javac commands.
+# This is useful to
+
+
+debug=0
+while getopts "d" opt; do
+case "$opt" in
+    d) debug=1 ;;
+esac
+done
+shift $(($OPTIND - 1))
+
+
+out=out
+
+rm -fr $out
+mkdir -p $out
+
+HOSTSTUBGEN=hoststubgen
+
+# Rebuild the tool and the dependencies. These are the only things we build with the build system.
+run m $HOSTSTUBGEN hoststubgen-annotations hoststubgen-helper-runtime truth-prebuilt junit
+
+
+# Build tiny-framework
+
+tiny_framework_classes=$out/tiny-framework/classes/
+tiny_framework_jar=$out/tiny-framework.jar
+tiny_framework_host_stub_jar=$out/tiny-framework_host_stub.jar
+tiny_framework_host_impl_jar=$out/tiny-framework_host_impl.jar
+
+tiny_test_classes=$out/tiny-test/classes/
+tiny_test_jar=$out/tiny-test.jar
+
+framework_compile_classpaths=(
+  $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/hoststubgen-annotations/android_common/javac/hoststubgen-annotations.jar
+)
+
+test_compile_classpaths=(
+  $SOONG_INT/external/junit/junit/android_common/combined/junit.jar
+  $SOONG_INT/prebuilts/tools/common/m2/truth-prebuilt/android_common/combined/truth-prebuilt.jar
+)
+
+test_runtime_classpaths=(
+  $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/hoststubgen-helper-runtime/linux_glibc_common/javac/hoststubgen-helper-runtime.jar
+)
+
+# This suite runs all tests in the JAR.
+test_classes=(com.android.hoststubgen.hosthelper.HostTestSuite)
+
+# Uncomment this to run a specific test.
+# tests=(com.android.hoststubgen.test.tinyframework.TinyFrameworkBenchmark)
+
+
+# Build tiny-framework.jar
+echo "# Building tiny-framework..."
+run $JAVAC \
+    -cp $( \
+        join : \
+        ${framework_compile_classpaths[@]} \
+        ) \
+    -d $tiny_framework_classes \
+    tiny-framework/src/**/*.java
+
+run $JAR cvf $tiny_framework_jar \
+    -C $tiny_framework_classes .
+
+# Build stub/impl jars
+echo "# Generating the stub and impl jars..."
+run $HOSTSTUBGEN \
+    @../hoststubgen-standard-options.txt \
+    --in-jar $tiny_framework_jar \
+    --out-stub-jar $tiny_framework_host_stub_jar \
+    --out-impl-jar $tiny_framework_host_impl_jar \
+    --policy-override-file policy-override-tiny-framework.txt \
+    --gen-keep-all-file out/tiny-framework_keep_all.txt \
+    --gen-input-dump-file out/tiny-framework_dump.txt \
+    $HOSTSTUBGEN_OPTS
+
+# Extract the jar files, so we can look into them.
+extract $tiny_framework_host_stub_jar $tiny_framework_host_impl_jar
+
+# Build the test
+echo "# Building tiny-test..."
+run $JAVAC \
+    -cp $( \
+        join : \
+        $tiny_framework_host_stub_jar \
+        "${test_compile_classpaths[@]}" \
+        ) \
+    -d $tiny_test_classes \
+    tiny-test/src/**/*.java
+
+run $JAR cvf $tiny_test_jar \
+    -C $tiny_test_classes .
+
+if (( $debug )) ; then
+  JAVA_OPTS="$JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8700"
+fi
+
+# Run the test
+echo "# Running tiny-test..."
+run $JAVA \
+    $JAVA_OPTS \
+    -cp $( \
+        join : \
+        $tiny_test_jar \
+        $tiny_framework_host_impl_jar \
+        "${test_compile_classpaths[@]}" \
+        "${test_runtime_classpaths[@]}" \
+        ) \
+    org.junit.runner.JUnitCore \
+    ${test_classes[@]}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
new file mode 100755
index 0000000..cee29dc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework-dump-test.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python3
+# 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.
+
+# Compare the tiny-framework JAR dumps to the golden files.
+
+import sys
+import os
+import unittest
+import subprocess
+
+GOLDEN_DIR = 'golden-output'
+
+# Run diff.
+def run_diff(file1, file2):
+    command = ['diff', '-u', '--ignore-blank-lines', '--ignore-space-change', file1, file2]
+    print(' '.join(command))
+    result = subprocess.run(command, stderr = sys.stdout)
+
+    success = result.returncode == 0
+
+    if success:
+        print(f'No diff found.')
+    else:
+        print(f'Fail: {file1} and {file2} are different.')
+
+    return success
+
+
+# Check one golden file.
+def check_one_file(filename):
+    print(f'= Checking file: {filename}')
+    return run_diff(os.path.join(GOLDEN_DIR, filename), filename)
+
+class TestWithGoldenOutput(unittest.TestCase):
+
+    # Test to check the generated jar files to the golden output.
+    def test_compare_to_golden(self):
+        files = os.listdir(GOLDEN_DIR)
+        files.sort()
+
+        print(f"Golden files: {files}")
+        success = True
+
+        for file in files:
+            if not check_one_file(file):
+                success = False
+
+        if not success:
+            self.fail('Some files are different. See stdout log for more details.')
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.java
new file mode 100644
index 0000000..f530207
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.java
@@ -0,0 +1,57 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestKeep;
+import android.hosttest.annotation.HostSideTestStub;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+/**
+ * Used by the benchmark.
+ */
+@HostSideTestWholeClassStub
+public class TinyFrameworkCallerCheck {
+
+    /**
+     * This method uses an inner method (which has the caller check).
+     *
+     * Benchmark result: 768ns
+     */
+    public static int getOne_withCheck() {
+        return Impl.getOneKeep();
+    }
+
+    /**
+     * This method doesn't have any caller check.
+     *
+     * Benchmark result: 2ns
+     */
+    public static int getOne_noCheck() {
+        return Impl.getOneStub();
+    }
+
+    private static class Impl {
+        @HostSideTestKeep
+        public static int getOneKeep() {
+            return 1;
+        }
+
+        @HostSideTestStub
+        public static int getOneStub() {
+            return 1;
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
new file mode 100644
index 0000000..ab387e0
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestKeep;
+import android.hosttest.annotation.HostSideTestRemove;
+import android.hosttest.annotation.HostSideTestStub;
+import android.hosttest.annotation.HostSideTestSubstitute;
+import android.hosttest.annotation.HostSideTestThrow;
+
+/**
+ * Test without class-wide annotations.
+ */
+@HostSideTestStub
+@HostSideTestClassLoadHook(
+        "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
+public class TinyFrameworkClassAnnotations {
+    @HostSideTestStub
+    public TinyFrameworkClassAnnotations() {
+    }
+
+    @HostSideTestStub
+    public int stub = 1;
+
+    @HostSideTestKeep
+    public int keep = 2;
+
+    // Members will be deleted by default.
+    // Deleted fields cannot have an initial value, because otherwise .ctor will fail to set it at
+    // runtime.
+    public int remove;
+
+    @HostSideTestStub
+    public int addOne(int value) {
+        return addOneInner(value);
+    }
+
+    @HostSideTestKeep
+    public int addOneInner(int value) {
+        return value + 1;
+    }
+
+    @HostSideTestRemove // Explicitly remove
+    public void toBeRemoved(String foo) {
+        throw new RuntimeException();
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public int addTwo(int value) {
+        throw new RuntimeException("not supported on host side");
+    }
+
+    public int addTwo_host(int value) {
+        return value + 2;
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public static native int nativeAddThree(int value);
+
+    public static int nativeAddThree_host(int value) {
+        return value + 3;
+    }
+
+    @HostSideTestThrow
+    public String unsupportedMethod() {
+        return "This value shouldn't be seen on the host side.";
+    }
+
+    @HostSideTestStub
+    public String visibleButUsesUnsupportedMethod() {
+        return unsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java
new file mode 100644
index 0000000..145b65a
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations.java
@@ -0,0 +1,74 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestStub;
+import android.hosttest.annotation.HostSideTestSubstitute;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkClassClassWideAnnotations {
+    public TinyFrameworkClassClassWideAnnotations() {
+    }
+
+    public int stub = 1;
+
+    public int keep = 2;
+
+    // Cannot have an initial value, because otherwise .ctor will fail to set it at runtime.
+    public int remove;
+
+    // @Stub
+    public int addOne(int value) {
+        return addOneInner(value);
+    }
+
+    // @Keep
+    public int addOneInner(int value) {
+        return value + 1;
+    }
+
+    // @Remove
+    public void toBeRemoved(String foo) {
+        throw new RuntimeException();
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public int addTwo(int value) {
+        throw new RuntimeException("not supported on host side");
+    }
+
+    public int addTwo_host(int value) {
+        return value + 2;
+    }
+
+    @HostSideTestStub
+    @HostSideTestSubstitute(suffix = "_host")
+    public static native int nativeAddThree(int value);
+
+    public static int nativeAddThree_host(int value) {
+        return value + 3;
+    }
+
+    public String unsupportedMethod() {
+        return "This value shouldn't be seen on the host side.";
+    }
+
+    public String visibleButUsesUnsupportedMethod() {
+        return unsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
new file mode 100644
index 0000000..98fc634
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkClassLoadHook {
+    private TinyFrameworkClassLoadHook() {
+    }
+
+    public static final Set<Class<?>> sLoadedClasses = new HashSet<>();
+
+    public static void onClassLoaded(Class<?> clazz) {
+        sLoadedClasses.add(clazz);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
new file mode 100644
index 0000000..53cfdf6
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestClassLoadHook;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestClassLoadHook(
+        "com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded")
+@HostSideTestWholeClassStub
+public class TinyFrameworkClassWithInitializer {
+    static {
+        sInitialized = true;
+    }
+
+    public static boolean sInitialized;
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
new file mode 100644
index 0000000..909d3b4
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.java
@@ -0,0 +1,29 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkExceptionTester {
+    public static int testException() {
+        try {
+            throw new IllegalStateException("Inner exception");
+        } catch (Exception e) {
+            throw new RuntimeException("Outer exception", e);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
new file mode 100644
index 0000000..bde7c35
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+/**
+ * Class for testing the "text policy" file.
+ */
+public class TinyFrameworkForTextPolicy {
+    public TinyFrameworkForTextPolicy() {
+    }
+
+    public int stub = 1;
+
+    public int keep = 2;
+
+    // Removed fields cannot have an initial value, because otherwise .ctor will fail to set it at
+    // runtime.
+    public int remove;
+
+    public int addOne(int value) {
+        return addOneInner(value);
+    }
+
+    public int addOneInner(int value) {
+        return value + 1;
+    }
+
+    public void toBeRemoved(String foo) {
+        throw new RuntimeException();
+    }
+
+    public int addTwo(int value) {
+        throw new RuntimeException("not supported on host side");
+    }
+
+    public int addTwo_host(int value) {
+        return value + 2;
+    }
+
+    public static native int nativeAddThree(int value);
+
+    public static int addThree_host(int value) {
+        return value + 3;
+    }
+
+    public String unsupportedMethod() {
+        return "This value shouldn't be seen on the host side.";
+    }
+
+    public String visibleButUsesUnsupportedMethod() {
+        return unsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
new file mode 100644
index 0000000..c151dcc
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestNativeSubstitutionClass;
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+@HostSideTestWholeClassStub
+@HostSideTestNativeSubstitutionClass("TinyFrameworkNative_host")
+public class TinyFrameworkNative {
+    public static native int nativeAddTwo(int arg);
+
+    public static int nativeAddTwo_should_be_like_this(int arg) {
+        return TinyFrameworkNative_host.nativeAddTwo(arg);
+    }
+
+    public static native long nativeLongPlus(long arg1, long arg2);
+
+    public static long nativeLongPlus_should_be_like_this(long arg1, long arg2) {
+        return TinyFrameworkNative_host.nativeLongPlus(arg1, arg2);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
new file mode 100644
index 0000000..48f7dea
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassKeep;
+
+// TODO: This annotation shouldn't be needed.
+// We should infer it from HostSideTestNativeSubstitutionClass.
+@HostSideTestWholeClassKeep
+public class TinyFrameworkNative_host {
+    public static int nativeAddTwo(int arg) {
+        return arg + 2;
+    }
+
+    public static long nativeLongPlus(long arg1, long arg2) {
+        return arg1 + arg2;
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
new file mode 100644
index 0000000..e1c48bb
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.java
@@ -0,0 +1,87 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+import android.hosttest.annotation.HostSideTestWholeClassStub;
+
+import java.util.function.Supplier;
+
+@HostSideTestWholeClassStub
+public class TinyFrameworkNestedClasses {
+    public final Supplier<Integer> mSupplier = new Supplier<Integer>() {
+        @Override
+        public Integer get() {
+            return 1;
+        }
+    };
+
+    public static final Supplier<Integer> sSupplier =  new Supplier<Integer>() {
+        @Override
+        public Integer get() {
+            return 2;
+        }
+    };
+    public Supplier<Integer> getSupplier() {
+        return new Supplier<Integer>() {
+            @Override
+            public Integer get() {
+                return 3;
+            }
+        };
+    }
+
+    public static Supplier<Integer> getSupplier_static() {
+        return new Supplier<Integer>() {
+            @Override
+            public Integer get() {
+                return 4;
+            }
+        };
+    }
+
+    @HostSideTestWholeClassStub
+    public class InnerClass {
+        public int value = 5;
+    }
+
+    @HostSideTestWholeClassStub
+    public static class StaticNestedClass {
+        public int value = 6;
+
+        // Double-nest
+        public static Supplier<Integer> getSupplier_static() {
+            return new Supplier<Integer>() {
+                @Override
+                public Integer get() {
+                    return 7;
+                }
+            };
+        }
+    }
+
+    public static class BaseClass {
+        public int value;
+        public BaseClass(int x) {
+            value = x;
+        }
+    }
+
+    public static class SubClass extends BaseClass {
+        public SubClass(int x) {
+            super(x);
+        }
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkBenchmark.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkBenchmark.java
new file mode 100644
index 0000000..6b5110e
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkBenchmark.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import org.junit.Test;
+
+import java.text.DecimalFormat;
+
+/**
+ * Contains simple micro-benchmarks.
+ */
+public class TinyFrameworkBenchmark {
+    private static final int MINIMAL_ITERATION = 1000;
+    private static final int MEASURE_SECONDS = 3;
+
+    private static final DecimalFormat sFormatter = new DecimalFormat("#,###");
+
+    private void doBenchmark(String name, Runnable r) {
+        // Worm up
+        for (int i = 0; i < MINIMAL_ITERATION; i++) {
+            r.run();
+        }
+
+        // Start measuring.
+        final long start = System.nanoTime();
+        final long end = start + MEASURE_SECONDS * 1_000_000_000L;
+
+        double iteration = 0;
+        while (System.nanoTime() <= end) {
+            for (int i = 0; i < MINIMAL_ITERATION; i++) {
+                r.run();
+            }
+            iteration += MINIMAL_ITERATION;
+        }
+
+        final long realEnd = System.nanoTime();
+
+        System.out.println(String.format("%s\t%s", name,
+                sFormatter.format((((double) realEnd - start)) / iteration)));
+    }
+
+    /**
+     * Micro-benchmark for a method without a non-stub caller check.
+     */
+    @Test
+    public void benchNoCallerCheck() {
+        doBenchmark("No caller check", TinyFrameworkCallerCheck::getOne_noCheck);
+    }
+
+    /**
+     * Micro-benchmark for a method with a non-stub caller check.
+     */
+    @Test
+    public void benchWithCallerCheck() {
+        doBenchmark("With caller check", TinyFrameworkCallerCheck::getOne_withCheck);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
new file mode 100644
index 0000000..246d065
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.hoststubgen.test.tinyframework;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TinyFrameworkClassTest {
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void testSimple() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+        assertThat(tfc.addOne(1)).isEqualTo(2);
+        assertThat(tfc.stub).isEqualTo(1);
+    }
+
+//    @Test
+//    public void testDoesntCompile() {
+//        TinyFrameworkClass tfc = new TinyFrameworkClass();
+//
+//        tfc.addOneInner(1); // Shouldn't compile.
+//        tfc.toBeRemoved("abc"); // Shouldn't compile.
+//        tfc.unsupportedMethod(); // Shouldn't compile.
+//        int a = tfc.keep; // Shouldn't compile
+//        int b = tfc.remove; // Shouldn't compile
+//    }
+
+    @Test
+    public void testSubstitute() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+        assertThat(tfc.addTwo(1)).isEqualTo(3);
+    }
+
+    @Test
+    public void testSubstituteNative() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+        assertThat(tfc.nativeAddThree(1)).isEqualTo(4);
+    }
+
+    @Test
+    public void testVisibleButUsesUnsupportedMethod() {
+        TinyFrameworkForTextPolicy tfc = new TinyFrameworkForTextPolicy();
+
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("This method is not supported on the host side");
+        tfc.visibleButUsesUnsupportedMethod();
+    }
+
+    @Test
+    public void testNestedClass1() {
+        assertThat(new TinyFrameworkNestedClasses().mSupplier.get()).isEqualTo(1);
+    }
+
+    @Test
+    public void testNestedClass2() {
+        assertThat(TinyFrameworkNestedClasses.sSupplier.get()).isEqualTo(2);
+    }
+
+    @Test
+    public void testNestedClass3() {
+        assertThat(new TinyFrameworkNestedClasses().getSupplier().get()).isEqualTo(3);
+    }
+
+    @Test
+    public void testNestedClass4() {
+        assertThat(TinyFrameworkNestedClasses.getSupplier_static().get()).isEqualTo(4);
+    }
+
+    @Test
+    public void testNestedClass5() {
+        assertThat((new TinyFrameworkNestedClasses()).new InnerClass().value).isEqualTo(5);
+    }
+
+    @Test
+    public void testNestedClass6() {
+        assertThat(new TinyFrameworkNestedClasses.StaticNestedClass().value).isEqualTo(6);
+    }
+
+    @Test
+    public void testNestedClass7() {
+        assertThat(TinyFrameworkNestedClasses.StaticNestedClass.getSupplier_static().get())
+                .isEqualTo(7);
+    }
+
+    @Test
+    public void testNativeSubstitutionClass() {
+        assertThat(TinyFrameworkNative.nativeAddTwo(3)).isEqualTo(5);
+    }
+
+    @Test
+    public void testExitLog() {
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("Outer exception");
+
+        TinyFrameworkExceptionTester.testException();
+
+    }
+
+    @Test
+    public void testMethodCallBeforeSuperCall() {
+        assertThat(new SubClass(3).value).isEqualTo(3);
+    }
+
+    @Test
+    public void testClassLoadHook() {
+        assertThat(TinyFrameworkClassWithInitializer.sInitialized).isTrue();
+
+        // Having this line before assertThat() will ensure these class are already loaded.
+        var classes = new Class[] {
+                TinyFrameworkClassWithInitializer.class,
+                TinyFrameworkClassAnnotations.class,
+                TinyFrameworkForTextPolicy.class,
+        };
+
+        // The following classes have a class load hook, so they should be registered.
+        assertThat(TinyFrameworkClassLoadHook.sLoadedClasses)
+                .containsAnyIn(classes);
+
+        // This class doesn't have a class load hook, so shouldn't be included.
+        assertThat(TinyFrameworkClassLoadHook.sLoadedClasses)
+                .doesNotContain(TinyFrameworkNestedClasses.class);
+    }
+}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java
new file mode 100644
index 0000000..20cc2ec
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithAnnotTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.hoststubgen.test.tinyframework;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class TinyFrameworkClassWithAnnotTest {
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Test
+    public void testSimple() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+        assertThat(tfc.addOne(1)).isEqualTo(2);
+        assertThat(tfc.stub).isEqualTo(1);
+    }
+
+//    @Test
+//    public void testDoesntCompile() {
+//        TinyFrameworkClassWithAnnot tfc = new TinyFrameworkClassWithAnnot();
+//
+//        tfc.addOneInner(1); // Shouldn't compile.
+//        tfc.toBeRemoved("abc"); // Shouldn't compile.
+//        tfc.unsupportedMethod(); // Shouldn't compile.
+//        int a = tfc.keep; // Shouldn't compile
+//        int b = tfc.remove; // Shouldn't compile
+//    }
+
+    @Test
+    public void testSubstitute() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+        assertThat(tfc.addTwo(1)).isEqualTo(3);
+    }
+
+    @Test
+    public void testSubstituteNative() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+        assertThat(tfc.nativeAddThree(1)).isEqualTo(4);
+    }
+
+    @Test
+    public void testVisibleButUsesUnsupportedMethod() {
+        TinyFrameworkClassAnnotations tfc = new TinyFrameworkClassAnnotations();
+
+        thrown.expect(RuntimeException.class);
+        thrown.expectMessage("This method is not supported on the host side");
+        tfc.visibleButUsesUnsupportedMethod();
+    }
+}
diff --git a/tools/hoststubgen/scripts/Android.bp b/tools/hoststubgen/scripts/Android.bp
new file mode 100644
index 0000000..5da805e
--- /dev/null
+++ b/tools/hoststubgen/scripts/Android.bp
@@ -0,0 +1,26 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+sh_binary_host {
+    name: "dump-jar",
+    src: "dump-jar",
+    visibility: ["//visibility:public"],
+}
+
+genrule_defaults {
+    name: "hoststubgen-jar-dump-defaults",
+    tools: ["dump-jar"],
+    cmd: "$(location dump-jar) -s -o $(out) $(in)",
+}
+
+sh_binary_host {
+    name: "run-ravenwood-test",
+    src: "run-ravenwood-test",
+    visibility: ["//visibility:public"],
+}
diff --git a/tools/hoststubgen/scripts/build-framework-hostside-jars-and-extract.sh b/tools/hoststubgen/scripts/build-framework-hostside-jars-and-extract.sh
new file mode 100755
index 0000000..7268123
--- /dev/null
+++ b/tools/hoststubgen/scripts/build-framework-hostside-jars-and-extract.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# 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.
+
+
+# Script to build `framework-host-stub` and `framework-host-impl`, and copy the
+# generated jars to $out, and unzip them. Useful for looking into the generated files.
+
+source "${0%/*}"/../common.sh
+
+out=framework-all-stub-out
+
+rm -fr $out
+mkdir -p $out
+
+# Build the jars with `m`.
+run m framework-all-hidden-api-host
+
+# Copy the jar to out/ and extract them.
+run cp \
+    $SOONG_INT/frameworks/base/tools/hoststubgen/hoststubgen/framework-all-hidden-api-host/linux_glibc_common/gen/* \
+    $out
+
+extract $out/*.jar
diff --git a/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh b/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
new file mode 100755
index 0000000..c3605a9
--- /dev/null
+++ b/tools/hoststubgen/scripts/build-framework-hostside-jars-without-genrules.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+# 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.
+
+
+# Script to build hoststubgen and run it directly (without using the build rules)
+# on framework-all.jar.
+
+
+echo "THIS SCRIPT IS BROKEN DUE TO CHANGES TO FILE PATHS TO DEPENDENT FILES. FIX IT WHEN YOU NEED TO USE IT." 1>&2
+
+exit 99
+
+
+source "${0%/*}"/../common.sh
+
+out=out
+
+mkdir -p $out
+
+# Build the tool and target jar.
+run m hoststubgen framework-all
+
+base_args=(
+  @../hoststubgen/hoststubgen-standard-options.txt
+
+  --in-jar $ANDROID_BUILD_TOP/out/soong/.intermediates/frameworks/base/framework-all/android_common/combined/framework-all.jar
+  --policy-override-file ../hoststubgen/framework-policy-override.txt "${@}"
+
+  # This file will contain all classes as an annotation file, with "keep all" policy.
+  --gen-keep-all-file $out/framework-all-keep-all-policy.txt
+
+  # This file will contains dump of all classes in the input jar.
+  --gen-input-dump-file $out/framework-all-dump.txt
+)
+
+do_it() {
+  local out_file_stem="$1"
+  shift
+  local extra_args=("${@}")
+
+  run hoststubgen \
+      "${base_args[@]}" \
+      "${extra_args[@]}" \
+      --out-stub-jar ${out_file_stem}_stub.jar \
+      --out-impl-jar ${out_file_stem}_impl.jar \
+      $HOSTSTUBGEN_OPTS
+
+  # Extract the jar files, so we can look into them.
+  run extract ${out_file_stem}_*.jar
+}
+
+#-----------------------------------------------------------------------------
+# framework-all, with all hidden APIs.
+#-----------------------------------------------------------------------------
+
+# No extra args.
+do_it $out/framework-all_host
+
+#-----------------------------------------------------------------------------
+# framework-test-api, only public/system/test-APIs in the stub.
+#-----------------------------------------------------------------------------
+
+do_it $out/framework-test-api_host \
+    --intersect-stub-jar $SOONG_INT/frameworks/base/api/android_test_stubs_current/android_common/combined/*.jar
diff --git a/tools/hoststubgen/scripts/dump-jar b/tools/hoststubgen/scripts/dump-jar
new file mode 100755
index 0000000..93729fb
--- /dev/null
+++ b/tools/hoststubgen/scripts/dump-jar
@@ -0,0 +1,163 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+
+help() {
+    cat <<'EOF'
+
+  dump-jar: Dump java classes in jar files
+
+    Usage:
+      dump-jar [-v] CLASS-FILE [...]
+
+        Dump a *.class file
+
+      dump-jar [-v] [-s] [-o OUTPUT-FILENAME] JAR-FILE[: filename regex] [...]
+
+        Dump a jar file.
+
+        If a filename contains a ':', then the following part
+        will be used to filter files in the jar file.
+
+        For example, "file.jar:/MyClass$" will only dump "MyClass" in file.jar.
+
+    Options:
+      -v: Enable verbose output.
+
+      -s: Simple output mode, used to check HostStubGen output jars.
+
+      -o: Write the output to a specified file.
+EOF
+}
+
+# Parse the options.
+
+verbose=0
+simple=0
+output=""
+while getopts "hvso:" opt; do
+case "$opt" in
+    h)
+        help
+        exit 0
+        ;;
+    v)
+        verbose=1
+        ;;
+    s)
+        simple=1
+        ;;
+    o)
+        output="$OPTARG"
+        ;;
+    '?')
+        help
+        exit 1
+        ;;
+esac
+done
+shift $(($OPTIND - 1))
+
+JAVAP_OPTS="${JAVAP_OPTS:--v -p -s -sysinfo -constants}"
+
+if (( $simple )) ; then
+  JAVAP_OPTS="-p -c -v"
+fi
+
+
+# Normalize a java class name.
+# Convert '.' to '/'
+# Remove the *.class suffix.
+normalize() {
+  local name="$1"
+  name="${name%.class}" # Remove the .class suffix.
+  echo "$name" | tr '.' '/'
+}
+
+# Convert the output for `-s` as needed.
+filter_output() {
+  if (( $simple )) ; then
+    # For "simple output" mode,
+    # - Normalize the constant numbers (replace with "#x")
+    # - Remove the constant pool
+    # - Remove the line number table
+    # - Some other transient lines
+    #
+    # `/PATTERN-1/,/PATTERN-1/{//!d}` is a trick to delete lines between two patterns, without
+    # the start and the end lines.
+    sed -e 's/#[0-9][0-9]*/#x/g' \
+        -e '/^Constant pool:/,/^[^ ]/{//!d}' \
+        -e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \
+        -e '/SHA-256 checksum/d' \
+        -e '/Last modified/d' \
+        -e '/^Classfile jar/d'
+  else
+    cat # Print as-is.
+  fi
+}
+
+# Write to the output file (specified with -o) as needed.
+write_to_out() {
+  if [[ -n "$output" ]] ; then
+    cat >"$output"
+    echo "Wrote output to $output" 1>&2
+  else
+    cat # print to stdout
+  fi
+}
+
+for file in "${@}"; do
+
+    # *.class?
+    if echo "$file" | grep -qE '\.class$' ; then
+        echo "# Class: $file" 1>&2
+        javap $dump_code_opt $JAVAP_OPTS $file
+
+    # *.jar?
+    elif echo "$file" | grep -qE '\.jar(:.*)?$' ; then
+        # Take the regex. Remove everything up to : in $file
+        regex=""
+        if [[ "$file" =~ : ]] ; then
+            regex="$(normalize "${file##*:}")"
+        fi
+
+        # Remove everything after ':', inclusively, in $file.
+        file="${file%:*}"
+
+        # Print the filename and the regex.
+        if ! (( $simple )) ; then
+          echo -n "# Jar: $file"
+          if [[ "$regex" != "" ]] ;then
+              echo -n "  (regex: $regex)"
+          fi
+          echo
+        fi
+
+        jar tf "$file" | grep '\.class$' | sort | while read -r class ; do
+            if normalize "$class" | grep -q -- "$regex" ; then
+                echo "## Class: $class"
+                javap $dump_code_opt $JAVAP_OPTS -cp $file ${class%.class}
+            else
+                (( $verbose )) && echo "## Skipping class: $class"
+            fi
+        done
+
+    else
+        echo "Unknown file type: $file" 1>&2
+        exit 1
+    fi
+done | filter_output | write_to_out
diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh
new file mode 100755
index 0000000..6bc0ddb
--- /dev/null
+++ b/tools/hoststubgen/scripts/run-all-tests.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# 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.
+
+source "${0%/*}"/../common.sh
+
+# Move to the top directory of hoststubgen
+cd ..
+
+# These tests are known to pass.
+READY_TEST_MODULES=(
+  HostStubGenTest-framework-all-test-host-test
+  hoststubgen-test-tiny-test
+)
+
+# First, build all the test modules. This shouldn't fail.
+run m run-ravenwood-test ${READY_TEST_MODULES[*]} ${NOT_READY_TEST_MODULES[*]}
+
+# Next, run the golden check. This should always pass too.
+# The following scripts _should_ pass too, but they depend on the internal paths to soong generated
+# files, and they may fail when something changes in the build system.
+run ./hoststubgen/test-tiny-framework/diff-and-update-golden.sh
+
+run ./hoststubgen/test-framework/run-test-without-atest.sh
+run ./hoststubgen/test-tiny-framework/run-test-manually.sh
+run ./scripts/build-framework-hostside-jars-and-extract.sh
+
+# This script is already broken on goog/master
+# run ./scripts/build-framework-hostside-jars-without-genrules.sh
+
+# These tests should all pass.
+run-ravenwood-test ${READY_TEST_MODULES[*]}
+
+echo ""${0##*/}" finished, with no unexpected failures. Ready to submit!"
\ No newline at end of file
diff --git a/tools/hoststubgen/scripts/run-ravenwood-test b/tools/hoststubgen/scripts/run-ravenwood-test
new file mode 100755
index 0000000..9bbb859
--- /dev/null
+++ b/tools/hoststubgen/scripts/run-ravenwood-test
@@ -0,0 +1,129 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+# Script to run a "Ravenwood" host side test.
+#
+# A proper way to run these tests is to use `atest`, but `atest` has a known issue of loading
+# unrelated jar files as the class path, so for now we use this script to run host side tests.
+
+# Copy (with some changes) some functions from ../common.sh, so this script can be used without it.
+
+m() {
+  if (( $SKIP_BUILD )) ; then
+    echo "Skipping build: $*" 1>&2
+    return 0
+  fi
+  run ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+run() {
+  echo "Running: $*" 1>&2
+  "$@"
+}
+
+run_junit_test_jar() {
+  local jar="$1"
+  echo "Starting test: $jar ..."
+  run cd "${jar%/*}"
+
+  run ${JAVA:-java} $JAVA_OPTS \
+      -cp $jar \
+      org.junit.runner.JUnitCore \
+      com.android.hoststubgen.hosthelper.HostTestSuite || return 1
+  return 0
+}
+
+help() {
+  cat <<'EOF'
+
+  run-ravenwood-test -- Run Ravenwood host tests
+
+  Usage:
+    run-ravenwood-test [options] MODULE-NAME ...
+
+  Options:
+    -h: Help
+    -t: Run test only, without building
+    -b: Build only, without running
+
+  Example:
+    run-ravenwood-test HostStubGenTest-framework-test-host-test
+
+EOF
+}
+
+#-------------------------------------------------------------------------
+# Parse options
+#-------------------------------------------------------------------------
+build=0
+test=0
+
+while getopts "htb" opt; do
+  case "$opt" in
+    h) help; exit 0 ;;
+    t)
+      test=1
+      ;;
+    b)
+      build=1
+      ;;
+  esac
+done
+shift $(($OPTIND - 1))
+
+# If neither -t nor -b is provided, then build and run./
+if (( ( $build + $test ) == 0 )) ; then
+  build=1
+  test=1
+fi
+
+
+modules=("${@}")
+
+if (( "${#modules[@]}" == 0 )); then
+  help
+  exit 1
+fi
+
+#-------------------------------------------------------------------------
+# Build
+#-------------------------------------------------------------------------
+if (( $build )) ; then
+  run m "${modules[@]}"
+fi
+
+#-------------------------------------------------------------------------
+# Run
+#-------------------------------------------------------------------------
+
+failures=0
+if (( test )) ; then
+  for module in "${modules[@]}"; do
+    if run_junit_test_jar "$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/${module}/${module}.jar"; then
+      : # passed.
+    else
+      failures=$(( failures + 1 ))
+    fi
+  done
+
+  if (( $failures > 0 )) ; then
+    echo "$failures test jar(s) failed." 1>&2
+    exit 2
+  fi
+fi
+
+exit 0
\ No newline at end of file
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
index 64808c0..7014068 100644
--- a/tools/obbtool/Main.cpp
+++ b/tools/obbtool/Main.cpp
@@ -135,7 +135,7 @@
     }
 
     printf("OBB info for '%s':\n", filename);
-    printf("Package name: %s\n", obb->getPackageName().string());
+    printf("Package name: %s\n", obb->getPackageName().c_str());
     printf("     Version: %d\n", obb->getVersion());
     printf("       Flags: 0x%08x\n", obb->getFlags());
     printf("     Overlay: %s\n", obb->isOverlay() ? "true" : "false");
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index 1e75117..73bfa19 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -257,7 +257,7 @@
                 usage();
                 return 1;
             }
-            targetConfigStr.setTo(*argv);
+            targetConfigStr = *argv;
         } else if (arg == "--split") {
             argc--;
             argv++;
@@ -281,7 +281,7 @@
                 usage();
                 return 1;
             }
-            baseApkPath.setTo(*argv);
+            baseApkPath = *argv;
         } else if (arg == "--generate") {
             generateFlag = true;
         } else if (arg == "--help") {
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
index 4e2b48e..c02e2d7 100644
--- a/tools/split-select/SplitDescription.cpp
+++ b/tools/split-select/SplitDescription.cpp
@@ -70,7 +70,7 @@
 String8 SplitDescription::toString() const {
     String8 extension;
     if (abi != abi::Variant_none) {
-        if (extension.isEmpty()) {
+        if (extension.empty()) {
             extension.append(":");
         } else {
             extension.append("-");
@@ -134,10 +134,10 @@
     String8 configStr;
     String8 extensionStr;
     if (index >= 0) {
-        configStr.setTo(str.c_str(), index);
-        extensionStr.setTo(str.c_str() + index + 1);
+        configStr = String8(str.c_str(), index);
+        extensionStr = (str.c_str() + index + 1);
     } else {
-        configStr.setTo(str);
+        configStr = str;
     }
 
     SplitDescription split;